繁体   English   中英

ScheduledThreadPoolExecutor 如何在特定时间运行任务?

[英]How does ScheduledThreadPoolExecutor run a task at a specific time?

特别是,它是否像这样在内部实现了一个 while-true 循环?

while (System.currentTimeMillis() < timeToRunTask){
    Thread.sleep(1000);
}

doTask();

http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/8u40-b25/java/util/concurrent/ScheduledThreadPoolExecutor.java#ScheduledThreadPoolExecutor.DelayedWorkQueue

一个任务将被装饰并放入 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM