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

时间:2017-08-30 09:12:54

标签: java

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

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

doTask();

1 个答案:

答案 0 :(得分:1)

来自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(...)返回之前,领导者线程必须发出一些其他线程的信号,除非其他一些线程成为临时的领导者。每当队列的头部被具有较早到期时间的任务替换时,通过被重置为空来使领导者字段无效,并且用信号通知一些等待线程,但不一定是当前领导者。因此,等待线程必须准备好在等待时获得并失去领导力。

来自对grepcode的评论。

请注意这是OpenJDK。 Oracle或其他JDK在实现方面可能有所不同。

您可以点击链接阅读Condition.awaitNanos