Motivation: All scheduled executors should behave in accordance to their API. The bug here is that scheduled tasks were not run more than once because we executed the runnables directly, instead of through the provided runnable future. Modification: We now run tasks through the provided future, so that when each run completes, the internal state of the task is reset and the ScheduledThreadPoolExecutor is informed of the completion. This allows the executor to prepare the next run. Result: The UnorderedThreadPoolEventExecutor is now able to run scheduled tasks more than once. Which is what one would expect from the API.
This commit is contained in:
parent
cd1581faad
commit
fd8c1874b4
@ -161,12 +161,12 @@ public final class UnorderedThreadPoolEventExecutor extends ScheduledThreadPoolE
|
||||
@Override
|
||||
protected <V> RunnableScheduledFuture<V> decorateTask(Runnable runnable, RunnableScheduledFuture<V> task) {
|
||||
return runnable instanceof NonNotifyRunnable ?
|
||||
task : new RunnableScheduledFutureTask<V>(this, runnable, task);
|
||||
task : new RunnableScheduledFutureTask<V>(this, task);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected <V> RunnableScheduledFuture<V> decorateTask(Callable<V> callable, RunnableScheduledFuture<V> task) {
|
||||
return new RunnableScheduledFutureTask<V>(this, callable, task);
|
||||
return new RunnableScheduledFutureTask<V>(this, task);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -213,15 +213,8 @@ public final class UnorderedThreadPoolEventExecutor extends ScheduledThreadPoolE
|
||||
implements RunnableScheduledFuture<V>, ScheduledFuture<V> {
|
||||
private final RunnableScheduledFuture<V> future;
|
||||
|
||||
RunnableScheduledFutureTask(EventExecutor executor, Runnable runnable,
|
||||
RunnableScheduledFuture<V> future) {
|
||||
super(executor, runnable);
|
||||
this.future = future;
|
||||
}
|
||||
|
||||
RunnableScheduledFutureTask(EventExecutor executor, Callable<V> callable,
|
||||
RunnableScheduledFuture<V> future) {
|
||||
super(executor, callable);
|
||||
RunnableScheduledFutureTask(EventExecutor executor, RunnableScheduledFuture<V> future) {
|
||||
super(executor, future);
|
||||
this.future = future;
|
||||
}
|
||||
|
||||
|
@ -19,6 +19,7 @@ import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class UnorderedThreadPoolEventExecutorTest {
|
||||
|
||||
@ -54,4 +55,22 @@ public class UnorderedThreadPoolEventExecutorTest {
|
||||
executor.shutdownGracefully();
|
||||
}
|
||||
}
|
||||
|
||||
@Test(timeout = 10000)
|
||||
public void scheduledAtFixedRateMustRunTaskRepeatedly() throws InterruptedException {
|
||||
UnorderedThreadPoolEventExecutor executor = new UnorderedThreadPoolEventExecutor(1);
|
||||
final CountDownLatch latch = new CountDownLatch(3);
|
||||
Future<?> future = executor.scheduleAtFixedRate(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
latch.countDown();
|
||||
}
|
||||
}, 1, 1, TimeUnit.MILLISECONDS);
|
||||
try {
|
||||
latch.await();
|
||||
} finally {
|
||||
future.cancel(true);
|
||||
executor.shutdownGracefully();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -152,7 +152,12 @@ public class EpollSocketChannelConfigTest {
|
||||
ch.config().getSoLinger();
|
||||
fail();
|
||||
} catch (ChannelException e) {
|
||||
assertTrue(e.getCause() instanceof ClosedChannelException);
|
||||
if (!(e.getCause() instanceof ClosedChannelException)) {
|
||||
AssertionError error = new AssertionError(
|
||||
"Expected the suppressed exception to be an instance of ClosedChannelException.");
|
||||
error.addSuppressed(e.getCause());
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user