Reduce synchronization overhead in HashedWheelTimer.start/stop()

This commit is contained in:
Trustin Lee 2012-10-16 13:36:36 -07:00
parent b75ab6171c
commit 543cb17acd

View File

@ -23,7 +23,6 @@ import java.util.Set;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock;
@ -90,7 +89,7 @@ public class HashedWheelTimer implements Timer {
private final Worker worker = new Worker(); private final Worker worker = new Worker();
final Thread workerThread; final Thread workerThread;
final AtomicBoolean shutdown = new AtomicBoolean(); final AtomicInteger workerState = new AtomicInteger(); // 0 - init, 1 - started, 2 - shut down
private final long roundDuration; private final long roundDuration;
final long tickDuration; final long tickDuration;
@ -257,17 +256,23 @@ public class HashedWheelTimer implements Timer {
* @throws IllegalStateException if this timer has been * @throws IllegalStateException if this timer has been
* {@linkplain #stop() stopped} already * {@linkplain #stop() stopped} already
*/ */
public synchronized void start() { public void start() {
if (shutdown.get()) { switch (workerState.get()) {
throw new IllegalStateException("cannot be started once stopped"); case 0:
} if (workerState.compareAndSet(0, 1)) {
if (!workerThread.isAlive()) {
workerThread.start(); workerThread.start();
} }
break;
case 1:
break;
case 2:
throw new IllegalStateException("cannot be started once stopped");
default:
throw new Error();
}
} }
public synchronized Set<Timeout> stop() { public Set<Timeout> stop() {
if (Thread.currentThread() == workerThread) { if (Thread.currentThread() == workerThread) {
throw new IllegalStateException( throw new IllegalStateException(
HashedWheelTimer.class.getSimpleName() + HashedWheelTimer.class.getSimpleName() +
@ -275,7 +280,9 @@ public class HashedWheelTimer implements Timer {
TimerTask.class.getSimpleName()); TimerTask.class.getSimpleName());
} }
if (!shutdown.compareAndSet(false, true)) { if (!workerState.compareAndSet(1, 2)) {
// workerState can be 0 or 2 at this moment - let it always be 2.
workerState.set(2);
return Collections.emptySet(); return Collections.emptySet();
} }
@ -314,9 +321,7 @@ public class HashedWheelTimer implements Timer {
throw new NullPointerException("unit"); throw new NullPointerException("unit");
} }
if (!workerThread.isAlive()) {
start(); start();
}
delay = unit.toMillis(delay); delay = unit.toMillis(delay);
HashedWheelTimeout timeout = new HashedWheelTimeout(task, currentTime + delay); HashedWheelTimeout timeout = new HashedWheelTimeout(task, currentTime + delay);
@ -369,7 +374,7 @@ public class HashedWheelTimer implements Timer {
startTime = System.currentTimeMillis(); startTime = System.currentTimeMillis();
tick = 1; tick = 1;
while (!shutdown.get()) { while (workerState.get() == 1) {
final long deadline = waitForNextTick(); final long deadline = waitForNextTick();
if (deadline > 0) { if (deadline > 0) {
fetchExpiredTimeouts(expiredTimeouts, deadline); fetchExpiredTimeouts(expiredTimeouts, deadline);
@ -463,7 +468,7 @@ public class HashedWheelTimer implements Timer {
try { try {
Thread.sleep(sleepTime); Thread.sleep(sleepTime);
} catch (InterruptedException e) { } catch (InterruptedException e) {
if (shutdown.get()) { if (workerState.get() != 1) {
return -1; return -1;
} }
} }