563 |
|
(rs == SHUTDOWN && !workQueue.isEmpty())) |
564 |
|
return; |
565 |
|
if (workerCountOf(c) != 0) { // Eligible to terminate |
566 |
< |
interruptIdleWorkers(true); |
566 |
> |
interruptIdleWorkers(ONLY_ONE); |
567 |
|
return; |
568 |
|
} |
569 |
|
if (ctl.compareAndSet(c, ctlOf(TERMINATED, 0))) { |
651 |
|
* called only from tryTerminate when termination is otherwise |
652 |
|
* enabled but there are still other workers. In this case, at |
653 |
|
* most one waiting worker is interrupted to propagate shutdown |
654 |
< |
* signals in case all threads are currently waiting. This |
655 |
< |
* suffices because all waiting workers existing at point of a |
656 |
< |
* shutdown() call must have already been interrupted. |
654 |
> |
* signals in case all threads are currently waiting. |
655 |
|
* Interrupting any arbitrary thread ensures that newly arriving |
656 |
|
* workers since shutdown began will also eventually exit. |
657 |
+ |
* To guarantee eventual termination, it suffices to always |
658 |
+ |
* interrupt only one idle worker, but shutdown() interrupts all |
659 |
+ |
* idle workers so that redundant workers exit promptly, not |
660 |
+ |
* waiting for a straggler task to finish. |
661 |
|
*/ |
662 |
|
private void interruptIdleWorkers(boolean onlyOne) { |
663 |
|
final ReentrantLock mainLock = this.mainLock; |
683 |
|
} |
684 |
|
} |
685 |
|
|
686 |
+ |
private void interruptIdleWorkers() { interruptIdleWorkers(false); } |
687 |
+ |
private static final boolean ONLY_ONE = true; |
688 |
+ |
|
689 |
|
/** |
690 |
|
* Ensures that unless the pool is stopping, the current thread |
691 |
|
* does not have its interrupt set. This requires a double-check |
782 |
|
for (;;) { |
783 |
|
int c = ctl.get(); |
784 |
|
int rs = runStateOf(c); |
785 |
< |
// Check if queue empty only if necessary, and re-read ctl |
781 |
< |
// after this call to make CAS more likely to succeed. |
785 |
> |
// Check if queue empty only if necessary. |
786 |
|
if (rs == SHUTDOWN) { |
787 |
|
if (workQueue.isEmpty()) |
788 |
|
return false; |
789 |
< |
if (runStateOf(c = ctl.get()) != rs) |
790 |
< |
continue; |
789 |
> |
// isEmpty() may be slow, so re-read ctl to reduce the risk |
790 |
> |
// of CAS failing due to harmless change to workerCount. |
791 |
> |
c = ctl.get(); |
792 |
|
} |
793 |
|
int wc = workerCountOf(c); |
794 |
|
if (rs > SHUTDOWN || |
1219 |
|
try { |
1220 |
|
checkShutdownAccess(); |
1221 |
|
advanceRunState(SHUTDOWN); |
1222 |
< |
interruptIdleWorkers(false); |
1222 |
> |
interruptIdleWorkers(); |
1223 |
|
onShutdown(); // hook for ScheduledThreadPoolExecutor |
1224 |
|
} finally { |
1225 |
|
mainLock.unlock(); |
1374 |
|
int delta = corePoolSize - this.corePoolSize; |
1375 |
|
this.corePoolSize = corePoolSize; |
1376 |
|
if (workerCountOf(ctl.get()) > corePoolSize) |
1377 |
< |
interruptIdleWorkers(false); |
1377 |
> |
interruptIdleWorkers(); |
1378 |
|
else if (delta > 0) { |
1379 |
|
// We don't really know how many new threads are "needed". |
1380 |
|
// As a heuristic, prestart enough new workers (up to new |
1461 |
|
if (value != allowCoreThreadTimeOut) { |
1462 |
|
allowCoreThreadTimeOut = value; |
1463 |
|
if (value) |
1464 |
< |
interruptIdleWorkers(false); |
1464 |
> |
interruptIdleWorkers(); |
1465 |
|
} |
1466 |
|
} |
1467 |
|
|
1482 |
|
throw new IllegalArgumentException(); |
1483 |
|
this.maximumPoolSize = maximumPoolSize; |
1484 |
|
if (workerCountOf(ctl.get()) > maximumPoolSize) |
1485 |
< |
interruptIdleWorkers(false); |
1485 |
> |
interruptIdleWorkers(); |
1486 |
|
} |
1487 |
|
|
1488 |
|
/** |
1517 |
|
long delta = keepAliveTime - this.keepAliveTime; |
1518 |
|
this.keepAliveTime = keepAliveTime; |
1519 |
|
if (delta < 0) |
1520 |
< |
interruptIdleWorkers(false); |
1520 |
> |
interruptIdleWorkers(); |
1521 |
|
} |
1522 |
|
|
1523 |
|
/** |