Java concurrent包中 DelayQueue 队头对象队延迟到期时间最长怎么理解?

Hardy
  • 7

阅读 Think in java 看到这么一种描述:我直接截图吧

clipboard.png
队头对象延迟时间最长但是 我执行代码执行结果是 延迟时间最短的先执行的啊。以下是代码:

package com.practice.concurrent.DelayedQueue;

import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.concurrent.TimeUnit.NANOSECONDS;
import static sun.misc.Version.print;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Delayed;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * 2017/12/18.
 */
public class DelayedTask implements Runnable, Delayed{

  private static int counter = 0;
  private final int id = counter++;
  private final int delat;
  private final long trigger;
  protected static List<DelayedTask> sequence =
      new ArrayList<DelayedTask>();

  public DelayedTask(int delayInMilliseconds){
    delat = delayInMilliseconds;
    trigger = System.nanoTime() +
        NANOSECONDS.convert(delat, MILLISECONDS);
    sequence.add(this);
  }

  @Override
  public long getDelay(TimeUnit unit) {
    return unit.convert(
        trigger - System.nanoTime(), NANOSECONDS
    );
  }

  @Override
  public int compareTo(Delayed arg) {
    DelayedTask that = (DelayedTask) arg;
    if (trigger < that.trigger) return -1;
    if (trigger > that.trigger) return 1;
    return 0;
  }

  @Override
  public void run() {

    System.out.println(this + " ");

  }

  public String toString(){
    return String.format("[%1$-4d]", delat) +
        " Task" + id;
  }

  public String summary(){
    return "(" + id + ":" + delat + ")" + "trigger + (" +trigger + ")";
  }

  public static class EndSentinel extends DelayedTask {
    private ExecutorService exec;
    public EndSentinel(int delay, ExecutorService e) {
      super(delay);
      exec = e;
    }
    public void run(){
      for (DelayedTask pt : sequence){
        System.out.println(pt.summary() + " ");
      }
      print();
      System.out.println(this + "Calling shutdownNow()");

      exec.shutdown();

    }
  }


}
package com.practice.concurrent.DelayedQueue;

import static jdk.nashorn.internal.objects.Global.print;

import java.util.concurrent.DelayQueue;
import java.util.concurrent.ExecutorService;

/**
 * 2017/12/18.
 */
class DelayedTaskConsumer implements Runnable{

  private DelayQueue<DelayedTask> q;
  private ExecutorService exec;

  public DelayedTaskConsumer(DelayQueue<DelayedTask> q, ExecutorService exec){
    this.q = q;
    this.exec = exec;
  }

  @Override
  public void run() {

    try {
      while (!exec.isShutdown()){
        q.take().run();
      }

    } catch (InterruptedException e) {
      e.printStackTrace();
    }
    System.out.println("Finished DelayedTaskConsumer");
  }


}

以下是执行demo

package com.practice.concurrent.DelayedQueue;

import java.util.Random;
import java.util.concurrent.DelayQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 2017/12/18.
 */
public class DelayQueueDemo {

  public static void main(String[] args) {
    Random rand = new Random(47);
    ExecutorService exec = Executors.newCachedThreadPool();
    DelayQueue<DelayedTask> queue =
        new DelayQueue<DelayedTask>();
    for (int i=0; i<20; i++){
      queue.put(new DelayedTask(rand.nextInt(5000)));
    }
    queue.add(new DelayedTask.EndSentinel(5000, exec));
    exec.execute(new DelayedTaskConsumer(queue, exec));
  }

}

运行结果如下:

[128 ] Task11  // 128延迟时间最短的先执行
[200 ] Task7 
[429 ] Task5 
[520 ] Task18 
[555 ] Task1 
[961 ] Task4 
[998 ] Task16 
[1207] Task9 
[1693] Task2 
[1809] Task14 
[1861] Task3 
[2278] Task15 
[3288] Task10 
[3551] Task12 
[4258] Task0 
[4258] Task19 
[4522] Task8 
[4589] Task13 
[4861] Task17 
[4868] Task6 
(0:4258)trigger + (22522182884813) 
(1:555)trigger + (22518480003523) 
(2:1693)trigger + (22519618020447) 
(3:1861)trigger + (22519786024736) 
(4:961)trigger + (22518886028495) 
(5:429)trigger + (22518354031877) 
(6:4868)trigger + (22522793035627) 
(7:200)trigger + (22518125038618) 
(8:4522)trigger + (22522447042259) 
(9:1207)trigger + (22519132045068) 
(10:3288)trigger + (22521213048113) 
(11:128)trigger + (22518053054251) 
(12:3551)trigger + (22521476063436) 
(13:4589)trigger + (22522514066333) 
(14:1809)trigger + (22519734069385) 
(15:2278)trigger + (22520203074247) 
(16:998)trigger + (22518923078353) 
(17:4861)trigger + (22522786081360) 
(18:520)trigger + (22518445084154) 
(19:4258)trigger + (22522183087267) 
(20:5000)trigger + (22522925605119) 
[5000] Task20Calling shutdownNow()
Finished DelayedTaskConsumer

大家可以看以下,还是我哪里理解有问题。现在绕在这儿解不开了 哈哈。

回复
阅读 2k
1 个回答

首先我得承认,目前本人思维还没有完全沉浸于多线程环境里。现在把这个过程重新描述一下:
1.创建单个任务实例时,传递的delayInMilliseconds值是从当前时间开始加上这个值得到的该任务最终应该执行的时间。
2.这样每个任务都会有一个自己的执行时间点。接下来,Thread1开始执行,那么剩下的 Thread2,Thread3 ……Thread 11 等一部分在Thread1执行过程中 也已经到期了。那么最紧急的在最前面,最紧急的当然是 到期时间最长的。这里是 已经到期时间最长的意思。我之前理解错了。
3.所以delay值最小的 一定是到期时间最长的了。

宣传栏