Please enable JavaScript.
Coggle requires JavaScript to display documents.
6.3 Finding Exploitable Parallelism - Coggle Diagram
6.3 Finding Exploitable Parallelism
General Concepts
Executor needs tasks as Runnable
Obvious task boundaries: Server (e.g., client request)
Less obvious: Desktop apps or within a single request
Goal: Identify opportunities for parallel execution
Result-Bearing Tasks: Callable & Future
Runnable Limitations
No return value
Can't throw checked exceptions
Can only have side effects
Callable Advantages
Returns a value via call()
Can throw checked exceptions
Use Callable<Void> for void-returning logic
Utility methods available to wrap Runnable as Callable
Task Lifecycle
Phases: Created → Submitted → Started → Completed
Tasks can be cancelled
Before starting → always cancellable
After starting → cancellable if interruptible
After completion → no effect
Future
Represents task lifecycle
Methods:
get() → Blocks until done
cancel() → Attempts cancellation
isDone() / isCancelled() → Check status
get() can throw:
ExecutionException → if task fails
CancellationException → if cancelled
Use getCause() to inspect root cause
How to Use
Submit Runnable or Callable to ExecutorService → returns Future
Can also use FutureTask
Implements Runnable
Can be submitted or run manually
Thread Safety
Submitting a task = safe publication
Setting result in Future = safe publication to consumers
Limitations of Parallelizing Heterogeneous Tasks
Challenges
Poor scalability with different task types
Uneven execution time leads to poor load balancing
Ex: Task A takes 10x time of Task B → limited speedup
Coordination overhead may negate gains
Overall: limited additional concurrency
Best Case
Works well with:
Many small, independent, homogeneous tasks
Minimal coordination needed
CompletionService: Combining Executor + BlockingQueue
What It Does
Manages task submission and result collection
Submits Callable tasks
Uses take() or poll() to retrieve results as they complete
Implementation
Uses a BlockingQueue for completed results
Wraps tasks in QueueingFuture (extends FutureTask)
Overrides done() to enqueue result
Delegates execution to a backing Executor
Time-Limited Tasks
Why Use Time Limits
Result may be useless after a deadline
Avoid wasting resources on overdue tasks
Using Future.get(timeout)
Blocks until result is ready
Throws TimeoutException if late
Handling Timeout
Option 1: Task self-monitors and exits
Option 2: Cancel via Future.cancel(true)
Only works if task is interruptible