220 |
|
* reclamation when large numbers of queued tasks become |
221 |
|
* cancelled.</dd> </dl> |
222 |
|
* |
223 |
+ |
* <p> <b>Extension example</b>. Most extensions of this class |
224 |
+ |
* override one or more of the protected hook methods. For example, |
225 |
+ |
* here is a subclass that adds a simple pause/resume feature: |
226 |
+ |
* |
227 |
+ |
* <pre> |
228 |
+ |
* class PausableThreadPoolExecutor extends ThreadPoolExecutor { |
229 |
+ |
* private boolean isPaused; |
230 |
+ |
* private ReentrantLock pauseLock = new ReentrantLock(); |
231 |
+ |
* private Condition unpaused = pauseLock.newCondition(); |
232 |
+ |
* |
233 |
+ |
* public PausableThreadPoolExecutor(...) { super(...); } |
234 |
+ |
* |
235 |
+ |
* protected void beforeExecute(Thread t, Runnable r) { |
236 |
+ |
* super.beforeExecute(t, r); |
237 |
+ |
* pauseLock.lock(); |
238 |
+ |
* try { |
239 |
+ |
* while (isPaused) unpaused.await(); |
240 |
+ |
* } catch(InterruptedException ie) { |
241 |
+ |
* Thread.currentThread().interrupt(); |
242 |
+ |
* } finally { |
243 |
+ |
* pauseLock.unlock(); |
244 |
+ |
* } |
245 |
+ |
* } |
246 |
+ |
* |
247 |
+ |
* public void pause() { |
248 |
+ |
* pauseLock.lock(); |
249 |
+ |
* try { |
250 |
+ |
* isPaused = true; |
251 |
+ |
* } finally { |
252 |
+ |
* pauseLock.unlock(); |
253 |
+ |
* } |
254 |
+ |
* } |
255 |
+ |
* |
256 |
+ |
* public void resume() { |
257 |
+ |
* pauseLock.lock(); |
258 |
+ |
* try { |
259 |
+ |
* isPaused = false; |
260 |
+ |
* unpaused.signalAll(); |
261 |
+ |
* } finally { |
262 |
+ |
* pauseLock.unlock(); |
263 |
+ |
* } |
264 |
+ |
* } |
265 |
+ |
* } |
266 |
+ |
* </pre> |
267 |
|
* @since 1.5 |
268 |
|
* @author Doug Lea |
269 |
|
*/ |
274 |
|
private static final Runnable[] EMPTY_RUNNABLE_ARRAY = new Runnable[0]; |
275 |
|
|
276 |
|
/** |
277 |
+ |
* Permission for checking shutdown |
278 |
+ |
*/ |
279 |
+ |
private static final RuntimePermission shutdownPerm = |
280 |
+ |
new RuntimePermission("modifyThread"); |
281 |
+ |
|
282 |
+ |
/** |
283 |
|
* Queue used for holding tasks and handing off to worker threads. |
284 |
|
*/ |
285 |
|
private final BlockingQueue<Runnable> workQueue; |
874 |
|
} |
875 |
|
|
876 |
|
public void shutdown() { |
877 |
+ |
// Fail if caller doesn't have modifyThread permission |
878 |
|
SecurityManager security = System.getSecurityManager(); |
879 |
|
if (security != null) |
880 |
< |
security.checkAccess(Thread.currentThread()); |
880 |
> |
java.security.AccessController.checkPermission(shutdownPerm); |
881 |
|
|
882 |
|
boolean fullyTerminated = false; |
883 |
|
mainLock.lock(); |
884 |
|
try { |
885 |
|
if (workers.size() > 0) { |
886 |
< |
if (runState == RUNNING) // don't override shutdownNow |
886 |
> |
// Check if caller can modify worker threads. |
887 |
> |
// This might not be true even if passed above check, |
888 |
> |
// if the securityManager treats some threads specially. |
889 |
> |
if (security != null) { |
890 |
> |
for (Worker w: workers) |
891 |
> |
security.checkAccess(w.thread); |
892 |
> |
} |
893 |
> |
|
894 |
> |
int state = runState; |
895 |
> |
if (state == RUNNING) // don't override shutdownNow |
896 |
|
runState = SHUTDOWN; |
897 |
< |
for (Worker w: workers) |
898 |
< |
w.interruptIfIdle(); |
897 |
> |
|
898 |
> |
try { |
899 |
> |
for (Worker w: workers) |
900 |
> |
w.interruptIfIdle(); |
901 |
> |
} catch(SecurityException se) { |
902 |
> |
// If SecurityManager allows above checks, but then |
903 |
> |
// unexpectedly throws exception when interrupting |
904 |
> |
// threads (which it ought not do), back out as |
905 |
> |
// cleanly as we can. -Some threads may have been |
906 |
> |
// killed but we remain in non-shutdown state. |
907 |
> |
runState = state; |
908 |
> |
throw se; |
909 |
> |
} |
910 |
|
} |
911 |
|
else { // If no workers, trigger full termination now |
912 |
|
fullyTerminated = true; |
922 |
|
|
923 |
|
|
924 |
|
public List<Runnable> shutdownNow() { |
925 |
+ |
// Almost the same code as shutdown() |
926 |
|
SecurityManager security = System.getSecurityManager(); |
927 |
|
if (security != null) |
928 |
< |
security.checkAccess(Thread.currentThread()); |
928 |
> |
java.security.AccessController.checkPermission(shutdownPerm); |
929 |
> |
|
930 |
|
boolean fullyTerminated = false; |
931 |
|
mainLock.lock(); |
932 |
|
try { |
933 |
|
if (workers.size() > 0) { |
934 |
< |
if (runState != TERMINATED) |
934 |
> |
if (security != null) { |
935 |
> |
for (Worker w: workers) |
936 |
> |
security.checkAccess(w.thread); |
937 |
> |
} |
938 |
> |
|
939 |
> |
int state = runState; |
940 |
> |
if (state != TERMINATED) |
941 |
|
runState = STOP; |
942 |
< |
for (Worker w : workers) |
943 |
< |
w.interruptNow(); |
942 |
> |
try { |
943 |
> |
for (Worker w : workers) |
944 |
> |
w.interruptNow(); |
945 |
> |
} catch(SecurityException se) { |
946 |
> |
runState = state; // back out; |
947 |
> |
throw se; |
948 |
> |
} |
949 |
|
} |
950 |
|
else { // If no workers, trigger full termination now |
951 |
|
fullyTerminated = true; |
1346 |
|
|
1347 |
|
/** |
1348 |
|
* Method invoked prior to executing the given Runnable in the |
1349 |
< |
* given thread. This method may be used to re-initialize |
1349 |
> |
* given thread. This method is invoked by thread <tt>t</tt> that |
1350 |
> |
* will execute task <tt>r</tt>, and may be used to re-initialize |
1351 |
|
* ThreadLocals, or to perform logging. Note: To properly nest |
1352 |
|
* multiple overridings, subclasses should generally invoke |
1353 |
|
* <tt>super.beforeExecute</tt> at the end of this method. |
1359 |
|
|
1360 |
|
/** |
1361 |
|
* Method invoked upon completion of execution of the given |
1362 |
< |
* Runnable. If non-null, the Throwable is the uncaught exception |
1362 |
> |
* Runnable. This method is invoked by the thread that executed |
1363 |
> |
* the task. If non-null, the Throwable is the uncaught exception |
1364 |
|
* that caused execution to terminate abruptly. Note: To properly |
1365 |
|
* nest multiple overridings, subclasses should generally invoke |
1366 |
|
* <tt>super.afterExecute</tt> at the beginning of this method. |