特别是,它是否在内部实现了一个while-true循环?
while (System.currentTimeMillis() < timeToRunTask){
Thread.sleep(1000);
}
doTask();
答案 0 :(得分:1)
任务将被装饰并放入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(...)返回之前,领导者线程必须发出一些其他线程的信号,除非其他一些线程成为临时的领导者。每当队列的头部被具有较早到期时间的任务替换时,通过被重置为空来使领导者字段无效,并且用信号通知一些等待线程,但不一定是当前领导者。因此,等待线程必须准备好在等待时获得并失去领导力。
来自对grepcode的评论。
请注意这是OpenJDK。 Oracle或其他JDK在实现方面可能有所不同。
您可以点击链接阅读Condition.awaitNanos
。