From 7950b849bc45faa07590838416f43f01df6de8b8 Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Wed, 28 Jul 2021 20:53:49 +1000 Subject: [PATCH] Alternative "fix" for #6495 updates from review --- .../util/thread/ReservedThreadExecutor.java | 39 +++++++++---------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/thread/ReservedThreadExecutor.java b/jetty-util/src/main/java/org/eclipse/jetty/util/thread/ReservedThreadExecutor.java index 585b7bb16257..bf8b17f4f6e7 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/thread/ReservedThreadExecutor.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/thread/ReservedThreadExecutor.java @@ -77,7 +77,8 @@ public String toString() private final AtomicLong _lastEmptyTime = new AtomicLong(Long.MAX_VALUE); private ThreadPoolBudget.Lease _lease; - private long _idleTimeMs = TimeUnit.MINUTES.toMillis(1); + private static final long DEFAULT_IDLE_TIMEOUT = TimeUnit.MINUTES.toNanos(1); + private long _idleTimeNanos = DEFAULT_IDLE_TIMEOUT; /** * @param executor The executor to use to obtain threads @@ -146,20 +147,20 @@ public int getPending() @ManagedAttribute(value = "idle timeout in ms", readonly = true) public long getIdleTimeoutMs() { - return _idleTimeMs; + return NANOSECONDS.toMillis(_idleTimeNanos); } /** * Set the idle timeout for shrinking the reserved thread pool * - * @param idleTime Time to wait before shrinking, or 0 for no timeout. + * @param idleTime Time to wait before shrinking, or 0 for default timeout. * @param idleTimeUnit Time units for idle timeout */ public void setIdleTimeout(long idleTime, TimeUnit idleTimeUnit) { if (isRunning()) throw new IllegalStateException(); - _idleTimeMs = (idleTime < 0 || idleTimeUnit == null) ? -1 : idleTimeUnit.toMillis(idleTime); + _idleTimeNanos = (idleTime <= 0 || idleTimeUnit == null) ? DEFAULT_IDLE_TIMEOUT : idleTimeUnit.toNanos(idleTime); } @Override @@ -179,7 +180,7 @@ public void doStop() throws Exception super.doStop(); // Offer STOP task to all waiting reserved threads. - for (int i = getLo(_count.getAndSet(-1)); i-- > 0;) + for (int i = _count.getAndSetLo(-1); i-- > 0;) { // yield to wait for any reserved threads that have incremented the size but not yet polled Thread.yield(); @@ -193,6 +194,7 @@ public void doStop() throws Exception thread.interrupt(); } _threads.clear(); + _count.getAndSetHi(0); } @Override @@ -305,26 +307,24 @@ private Runnable reservedWait() try { // Always poll at some period as safety to ensure we don't poll forever. - Runnable task = _queue.poll(_idleTimeMs <= 0 ? 30_000 : _idleTimeMs, TimeUnit.MILLISECONDS); + Runnable task = _queue.poll(_idleTimeNanos, NANOSECONDS); if (LOG.isDebugEnabled()) LOG.debug("{} task={} {}", this, task, ReservedThreadExecutor.this); if (task != null) return task; - // Have we idled out? - if (_idleTimeMs > 0) + // we have idled out + int size = _count.getLo(); + // decrement size if we have not also been stopped. + while (size > 0) { - int size = _count.getLo(); - // decrement size if we have not also been stopped. - while (size > 0) - { - if (_count.compareAndSetLo(size, --size)) - break; - size = _count.getLo(); - } - _state = size >= 0 ? State.IDLE : State.STOPPED; - return STOP; + if (_count.compareAndSetLo(size, --size)) + break; + size = _count.getLo(); } + _state = size >= 0 ? State.IDLE : State.STOPPED; + return STOP; + } catch (InterruptedException e) { @@ -359,8 +359,7 @@ public void run() { long now = System.nanoTime(); long lastEmpty = _lastEmptyTime.get(); - if (size > 0 && _idleTimeMs > 0 && _idleTimeMs < NANOSECONDS.toMillis(now - lastEmpty) && - _lastEmptyTime.compareAndSet(lastEmpty, now)) + if (size > 0 && _idleTimeNanos < (now - lastEmpty) && _lastEmptyTime.compareAndSet(lastEmpty, now)) { // it has been too long since we hit zero reserved threads, so are "busy" idle next = State.IDLE;