Executor separates submitting a Runnable from deciding where it runs.
ExecutorService adds lifecycle management and submit; Callable<V> can
return a value or throw a checked exception, and Future<V> represents the
eventual result. Future.get() establishes the required visibility of actions
performed by the task before completion.
Future<Result> future = pool.submit(() -> compute(input));
try {
return future.get();
} catch (ExecutionException e) {
throw new ServiceException(e.getCause());
}Use synchronized, Lock, atomics, concurrent collections, or message
passing to establish happens-before relationships. An executor supplies
scheduling, not automatic safety for mutable shared objects.
AQS and Synchronizers #
AbstractQueuedSynchronizer (AQS) is a framework for locks, semaphores,
latches, and related synchronizers. A subclass maintains an atomic integer
state and implements acquire/release attempts. On contention, AQS enqueues
waiting threads in a FIFO-style synchronization queue and parks them with
LockSupport; release unparks eligible successors. Conditions use associated
condition queues and transfer waiters back to the synchronization queue when
signalled. Queue order is not, by itself, a universal fairness guarantee.
ThreadPoolExecutor Admission #
ThreadPoolExecutor first creates workers up to corePoolSize; it then queues
tasks; only when the queue rejects a task does it grow toward
maximumPoolSize; after that it rejects. Consequently an unbounded
LinkedBlockingQueue effectively prevents growth beyond core threads, while a
SynchronousQueue creates workers aggressively until the maximum. Idle workers
above the core size terminate after keepAliveTime; core threads may also time
out when explicitly enabled.
Choose a bounded queue and size it from workload evidence, memory limits, and
the downstream system’s capacity. The worker factory controls names, daemon
status, and uncaught-exception handling. AbortPolicy throws,
CallerRunsPolicy applies backpressure by running on the submitter,
DiscardPolicy drops work, and DiscardOldestPolicy removes queued work before
retrying. Silent dropping is acceptable only when callers can tolerate it.
Lifecycle, Cancellation, and Visibility #
cancel(true) marks a Future cancelled and requests interruption if the task
is running; interruption is cooperative, so blocking operations must propagate
or restore the interrupted status and CPU-bound tasks must poll it. Cancellation
does not roll back side effects.
shutdown() rejects new tasks while allowing queued tasks to finish.
shutdownNow() attempts to interrupt workers and returns tasks never begun.
Call awaitTermination at application boundaries. Executors factory methods
provide fixed, single-thread, scheduled, work-stealing, and virtual-thread
executors in current JDKs, but explicit ThreadPoolExecutor construction makes
queueing and rejection policy reviewable. Always close an ExecutorService
when its lifetime is lexical.
Comments
Read or comment on GitHub (sign-in required to comment)