[英]How does ScheduledThreadPoolExecutor run a task at a specific time?
特别是,它是否像这样在内部实现了一个 while-true 循环?
while (System.currentTimeMillis() < timeToRunTask){
Thread.sleep(1000);
}
doTask();
一个任务将被装饰并放入 DelayedWorkQueue。 然后确保有一个线程尝试获取刚刚添加的条目。
public ScheduledFuture<?> schedule(Runnable command,
long delay,
TimeUnit unit) {
if (command == null || unit == null)
throw new NullPointerException();
RunnableScheduledFuture<?> t = decorateTask(command,
new ScheduledFutureTask<Void>(command, null,
triggerTime(delay, unit)));
delayedExecute(t);
return t;
}
private void delayedExecute(RunnableScheduledFuture<?> task) {
if (isShutdown())
reject(task);
else {
// Enqueue Task vv
super.getQueue().add(task);
if (isShutdown() &&
!canRunInCurrentRunState(task.isPeriodic()) &&
remove(task))
task.cancel(false);
else
// Make sure, there is a worker to be blocked
ensurePrestart();
}
}
take()
将在工作线程的 run() 中被调用。 实际延迟在这里:(见评论)
public RunnableScheduledFuture<?> take() throws InterruptedException {
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
for (;;) {
RunnableScheduledFuture<?> first = queue[0];
if (first == null)
// if queue is empty, wait (block) until signaled "not empty"
available.await();
else {
// compute how long Task still has to wait in NANOSECONDS
long delay = first.getDelay(NANOSECONDS);
// no further waiting? Then go on and execute!
if (delay <= 0)
return finishPoll(first);
first = null; // don't retain ref while waiting
if (leader != null) // leader/follower Pattern:
// see Comments in DeleyedWorkQueue
available.await();
else {
Thread thisThread = Thread.currentThread();
leader = thisThread;
try {
// ########## HERE IT COMES vvvvvvvvvvvvvvvvvvvvvvvvvvvv
available.awaitNanos(delay);
// Wait (block worker thread) for 'delay' nanos
} finally {
if (leader == thisThread)
leader = null;
}
}
}
}
} finally {
if (leader == null && queue[0] != null)
available.signal();
lock.unlock();
}
}
Leader-Follower 模式的这种变体 ( http://www.cs.wustl.edu/~schmidt/POSA/POSA2/ ) 用于最小化不必要的定时等待。 当一个线程成为领导者时,它只等待下一次延迟过去,而其他线程则无限期地等待。 领导线程必须在从 take() 或 poll(...) 返回之前向其他线程发出信号,除非某个其他线程在此期间成为领导。 每当队列的头部被具有较早到期时间的任务替换时,leader 字段将通过重置为空而无效,并且一些等待线程(但不一定是当前的leader)被发出信号。 因此,等待线程必须准备好在等待期间获得和失去领导权。
来自对 grepcode 的评论。
请注意,这是针对 OpenJDK 的。 Oracle 或其他 JDK 可能在实现上有所不同。
您可以通过以下链接了解Condition.awaitNanos
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.