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.127 by jsr166, Thu Dec 22 23:30:40 2011 UTC vs.
Revision 1.128 by jsr166, Sat Dec 24 02:13:42 2011 UTC

# Line 464 | Line 464 | public class ThreadPoolExecutor extends
464       * policy limiting the number of threads.  Even though it is not
465       * treated as an error, failure to create threads may result in
466       * new tasks being rejected or existing ones remaining stuck in
467 <     * the queue. On the other hand, no special precautions exist to
468 <     * handle OutOfMemoryErrors that might be thrown while trying to
469 <     * create threads, since there is generally no recourse from
470 <     * within this class.
467 >     * the queue.
468 >     *
469 >     * We go further and preserve pool invariants even in the face of
470 >     * errors such as OutOfMemoryError, that might be thrown while
471 >     * trying to create threads.  Such errors are rather common due to
472 >     * the need to allocate a native stack in Thread#start, and users
473 >     * will want to perform clean pool shutdown to clean up.  There
474 >     * will likely be enough memory available for the cleanup code to
475 >     * complete without encountering yet another OutOfMemoryError.
476       */
477      private volatile ThreadFactory threadFactory;
478  
# Line 835 | Line 840 | public class ThreadPoolExecutor extends
840       * Checks if a new worker can be added with respect to current
841       * pool state and the given bound (either core or maximum). If so,
842       * the worker count is adjusted accordingly, and, if possible, a
843 <     * new worker is created and started running firstTask as its
843 >     * new worker is created and started, running firstTask as its
844       * first task. This method returns false if the pool is stopped or
845       * eligible to shut down. It also returns false if the thread
846 <     * factory fails to create a thread when asked, which requires a
847 <     * backout of workerCount, and a recheck for termination, in case
848 <     * the existence of this worker was holding up termination.
846 >     * factory fails to create a thread when asked.  If the thread
847 >     * creation fails, either due to the thread factory returning
848 >     * null, or due to an exception (typically OutOfMemoryError in
849 >     * Thread#start), we roll back cleanly.
850       *
851       * @param firstTask the task the new thread should run first (or
852       * null if none). Workers are created with an initial first task
# Line 883 | Line 889 | public class ThreadPoolExecutor extends
889              }
890          }
891  
892 <        Worker w = new Worker(firstTask);
893 <        Thread t = w.thread;
888 <
889 <        final ReentrantLock mainLock = this.mainLock;
890 <        mainLock.lock();
892 >        boolean workerStarted = false;
893 >        Worker w = null;
894          try {
895 <            // Recheck while holding lock.
896 <            // Back out on ThreadFactory failure or if
897 <            // shut down before lock acquired.
898 <            int c = ctl.get();
899 <            int rs = runStateOf(c);
895 >            w = new Worker(firstTask);
896 >            final Thread t = w.thread;
897 >            final ReentrantLock mainLock = this.mainLock;
898 >            mainLock.lock();
899 >            try {
900 >                // Recheck while holding lock.
901 >                // Back out on ThreadFactory failure or if
902 >                // shut down before lock acquired.
903 >                int c = ctl.get();
904 >                int rs = runStateOf(c);
905 >
906 >                if (t == null ||
907 >                    (rs >= SHUTDOWN &&
908 >                     ! (rs == SHUTDOWN &&
909 >                        firstTask == null)))
910 >                    return false;
911  
912 <            if (t == null ||
913 <                (rs >= SHUTDOWN &&
914 <                 ! (rs == SHUTDOWN &&
915 <                    firstTask == null))) {
916 <                decrementWorkerCount();
917 <                tryTerminate();
918 <                return false;
912 >                workers.add(w);
913 >
914 >                int s = workers.size();
915 >                if (s > largestPoolSize)
916 >                    largestPoolSize = s;
917 >            } finally {
918 >                mainLock.unlock();
919              }
920  
921 <            workers.add(w);
921 >            t.start();
922 >            // It is possible (but unlikely) for a thread to have been
923 >            // added to workers, but not yet started, during transition to
924 >            // STOP, which could result in a rare missed interrupt,
925 >            // because Thread.interrupt is not guaranteed to have any
926 >            // effect on a non-yet-started Thread (see Thread#interrupt).
927 >            if (runStateOf(ctl.get()) == STOP && ! t.isInterrupted())
928 >                t.interrupt();
929  
930 <            int s = workers.size();
910 <            if (s > largestPoolSize)
911 <                largestPoolSize = s;
930 >            return workerStarted = true;
931          } finally {
932 <            mainLock.unlock();
932 >            if (! workerStarted)
933 >                addWorkerFailed(w);
934          }
935 +    }
936  
937 <        t.start();
938 <        // It is possible (but unlikely) for a thread to have been
939 <        // added to workers, but not yet started, during transition to
940 <        // STOP, which could result in a rare missed interrupt,
941 <        // because Thread.interrupt is not guaranteed to have any effect
942 <        // on a non-yet-started Thread (see Thread#interrupt).
943 <        if (runStateOf(ctl.get()) == STOP && ! t.isInterrupted())
944 <            t.interrupt();
945 <
946 <        return true;
937 >    /**
938 >     * Rolls back the worker thread creation.
939 >     * - removes worker from workers, if present
940 >     * - decrements worker count
941 >     * - rechecks for termination, in case the existence of this
942 >     *   worker was holding up termination
943 >     */
944 >    private void addWorkerFailed(Worker w) {
945 >        final ReentrantLock mainLock = this.mainLock;
946 >        mainLock.lock();
947 >        try {
948 >            if (w != null)
949 >                workers.remove(w);
950 >            decrementWorkerCount();
951 >            tryTerminate();
952 >        } finally {
953 >            mainLock.unlock();
954 >        }
955      }
956  
957      /**

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines