进阶篇:延时队列之DelayQueue(十四)

本文介绍 Java 中 DelayQueue 的使用方法,通过自定义 DelayTask 类实现基于 DelayQueue 的定时任务功能。DelayTask 类实现了 Delayed 和 Runnable 接口,通过 compareTo 方法确保任务按到期时间排序,getDelay 方法计算剩余等待时间。
摘要由CSDN通过智能技术生成

这篇文章我们来讲讲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毫秒内,   没错,一切都在我们的预料之中,延时时间越短的线程将先得到执行;


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值