ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/main/java/util/concurrent/ThreadPoolExecutor.java
(Generate patch)

Comparing jsr166/src/main/java/util/concurrent/ThreadPoolExecutor.java (file contents):
Revision 1.42 by dl, Wed Dec 17 17:00:24 2003 UTC vs.
Revision 1.43 by dl, Fri Dec 19 14:42:25 2003 UTC

# Line 220 | Line 220 | import java.util.*;
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   */
# Line 230 | Line 274 | public class ThreadPoolExecutor extends
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;
# Line 824 | Line 874 | public class ThreadPoolExecutor extends
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;
# Line 851 | Line 922 | public class ThreadPoolExecutor extends
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;
# Line 1262 | Line 1346 | public class ThreadPoolExecutor extends
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.
# Line 1274 | Line 1359 | public class ThreadPoolExecutor extends
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.

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines