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 |
|
|
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 |
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 |
|
/** |