这篇文章我们来讲讲BlockingQueue阻塞队列的另一个实现DelayQueue,先前我们的文章中有介绍LinkedBlockingQueue,而DelayQueue与之不同的是,DelayQueue里面哪怕有元素也无法取出,除非元素已经到期,而LinkedBlockingQueue只要里面有元素就可以取出!
所以,你可以往DelayQueue中存放一个元素,且声明在半小时后才失效。那么往此队列中取元素的线程将会阻塞半小时,直到半小时后才能拿到元素进行下一步动作,这样的话,你就可以变相实现定时执行任务了;当然,我们是不会这样来用的,定时任务有更完美的解决方案,这个我们后面再介绍;
class DelayTask implements Delayed,Runnable{
long trigger = 0;//触发时间,也就是队列中的元素失效时间
int id = 0;
long delayMilliSecound = 0;//等待时间
public DelayTask( long delayMilliSecound,int id) {
this.delayMilliSecound = delayMilliSecound;
this.trigger = System.currentTimeMillis()+delayMilliSecound;
this.id = id;
}
@Override
public int compareTo(Delayed arg) {
DelayTask delay = (DelayTask) arg;
if(this.trigger==delay.trigger){
return 0;
}
//必须要越晚到期的元素越排后,因为队列是先进先出的,最先弹出的元素是队头,所以队头必须是最先到期的
//当然,如果不这样做也不会有任何报错,只是,本来等待3秒某个任务必须要执行了
//但由于队头要等待10秒,在队头没有被弹出之前,该任务是无法弹出的;
return this.trigger > delay.trigger?1:-1;
}
//返回与此对象相关的剩余延迟时间,以给定的时间单位表示。
@Override
public long getDelay(TimeUnit unit) {
return unit.convert(trigger-System.currentTimeMillis(), TimeUnit.MILLISECONDS);
}
@Override
public void run() {
System.out.println("任务"+id+"开始运行,等待时间为:"+delayMilliSecound);
}
}
//DelayQueue,存放Delayed元素的一个无界阻塞队列,只有在某个元素的延迟期满时才能从中提取元素,它和LinkedBlockingQueue不同的是,
//DelayQueue里面哪怕有元素也无法取出,除非元素已经到期,也就是getDelay()返回值<=0;
//而LinkedBlockingQueue只要里面有元素就可以取出!
//DelayQueue也可以看成是一个变相的优先级队列;也就是说,越快失效的元素越能优先取出!
public static void delayQueue() throws InterruptedException{
final DelayQueue<DelayTask> queue = new DelayQueue<DelayTask>();
Random random = new Random();
for (int i = 0; i < 10; i++) {
queue.put(new DelayTask(random.nextInt(5000),i+1));
}
//开启一个消费者线程消费队列中的任务
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("开始消费队列中的任务!");
while( !Thread.currentThread().isInterrupted()){
try {
//取出队列中的元素
queue.take().run();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
//等任务全部消费完毕,再往队列里面塞一个ID为100,延期3秒的任务!
TimeUnit.MILLISECONDS.sleep(6000);
queue.put(new DelayTask(3000, 100));
}
注意:DelayQueue中存放的对象必须实现Delayed接口的compareTo方法与getDelay方法!
看一下输出:************************************************************************
开始消费队列中的任务!
任务4开始运行,等待时间为:554
任务9开始运行,等待时间为:729
任务5开始运行,等待时间为:917
任务3开始运行,等待时间为:1079
任务1开始运行,等待时间为:1652
任务10开始运行,等待时间为:2969
任务2开始运行,等待时间为:3676
任务7开始运行,等待时间为:3829
任务6开始运行,等待时间为:4252
任务8开始运行,等待时间为:4294
任务100开始运行,等待时间为:3000
**************************************************************************************
我们先往queue中塞入了十个DelayTask实例,且指定延时时间为随机5000毫秒内, 没错,一切都在我们的预料之中,延时时间越短的线程将先得到执行;