Main worker run loop. Repeatedly gets tasks from queue and
executes them, while coping with a number of issues:
1. We may start out with an initial task, in which case we
don't need to get the first one. Otherwise, as long as pool is
running, we get tasks from getTask. If it returns null then the
worker exits due to changed pool state or configuration
parameters. Other exits result from exception throws in
external code, in which case completedAbruptly holds, which
usually leads processWorkerExit to replace this thread.
2. Before running any task, the lock is acquired to prevent
other pool interrupts while the task is executing, and then we
ensure that unless pool is stopping, this thread does not have
its interrupt set.
3. Each task run is preceded by a call to beforeExecute, which
might throw an exception, in which case we cause thread to die
(breaking loop with completedAbruptly true) without processing
the task.
4. Assuming beforeExecute completes normally, we run the task,
gathering any of its thrown exceptions to send to afterExecute.
We separately handle RuntimeException, Error (both of which the
specs guarantee that we trap) and arbitrary Throwables.
Because we cannot rethrow Throwables within Runnable.run, we
wrap them within Errors on the way out (to the thread's
UncaughtExceptionHandler). Any thrown exception also
conservatively causes thread to die.
5. After task.run completes, we call afterExecute, which may
also throw an exception, which will also cause thread to
die. According to JLS Sec 14.20, this exception is the one that
will be in effect even if task.run throws.
The net effect of the exception mechanics is that afterExecute
and the thread's UncaughtExceptionHandler have as accurate
information as we can provide about any problems encountered by
user code.
Main worker run loop. Repeatedly gets tasks from queue and executes them, while coping with a number of issues:
1. We may start out with an initial task, in which case we don't need to get the first one. Otherwise, as long as pool is running, we get tasks from getTask. If it returns null then the worker exits due to changed pool state or configuration parameters. Other exits result from exception throws in external code, in which case completedAbruptly holds, which usually leads processWorkerExit to replace this thread.
2. Before running any task, the lock is acquired to prevent other pool interrupts while the task is executing, and then we ensure that unless pool is stopping, this thread does not have its interrupt set.
3. Each task run is preceded by a call to beforeExecute, which might throw an exception, in which case we cause thread to die (breaking loop with completedAbruptly true) without processing the task.
4. Assuming beforeExecute completes normally, we run the task, gathering any of its thrown exceptions to send to afterExecute. We separately handle RuntimeException, Error (both of which the specs guarantee that we trap) and arbitrary Throwables. Because we cannot rethrow Throwables within Runnable.run, we wrap them within Errors on the way out (to the thread's UncaughtExceptionHandler). Any thrown exception also conservatively causes thread to die.
5. After task.run completes, we call afterExecute, which may also throw an exception, which will also cause thread to die. According to JLS Sec 14.20, this exception is the one that will be in effect even if task.run throws.
The net effect of the exception mechanics is that afterExecute and the thread's UncaughtExceptionHandler have as accurate information as we can provide about any problems encountered by user code.
@param w the worker