概述
DelayQueue
是java.util.concurrent
中提供的一個(gè)很有意思的類蚊荣。本文將會(huì)對(duì)DelayQueue
做一個(gè)介紹,然后列舉應(yīng)用場(chǎng)景。并且提供一個(gè)Delayed
接口的實(shí)現(xiàn)和 Sample 代碼。
DelayQueue
是一個(gè)無(wú)界的BlockingQueue
江滨,用于放置實(shí)現(xiàn)了Delayed
接口的對(duì)象,其中的對(duì)象只能在其到期時(shí)才能從隊(duì)列中取走厌均。這種隊(duì)列是有序的唬滑,即隊(duì)頭對(duì)象的延遲到期時(shí)間最長(zhǎng)。注意:不能將null元素放置到這種隊(duì)列中棺弊。
Delayed晶密,一種混合風(fēng)格的接口,用來(lái)標(biāo)記那些應(yīng)該在給定延遲時(shí)間之后執(zhí)行的對(duì)象模她。Delayed擴(kuò)展了Comparable
接口稻艰,比較的基準(zhǔn)為延時(shí)的時(shí)間值,Delayed
接口的實(shí)現(xiàn)類getDelay的返回值應(yīng)為固定值(final
)侈净。DelayQueue
內(nèi)部是使用PriorityQueue
實(shí)現(xiàn)的尊勿。
應(yīng)用舉例
DelayQueue
阻塞隊(duì)列在我們系統(tǒng)開發(fā)中也常常會(huì)用到,例如:緩存系統(tǒng)的設(shè)計(jì)畜侦,緩存中的對(duì)象元扔,超過(guò)了空閑時(shí)間,需要從緩存中移出旋膳;任務(wù)調(diào)度系統(tǒng)澎语,能夠準(zhǔn)確的把握任務(wù)的執(zhí)行時(shí)間。我們可能需要通過(guò)線程處理很多時(shí)間上要求很嚴(yán)格的數(shù)據(jù),如果使用普通的線程擅羞,我們就需要遍歷所有的對(duì)象尸变,一個(gè)一個(gè)的檢查看數(shù)據(jù)是否過(guò)期等,首先這樣在執(zhí)行上的效率不會(huì)太高减俏,其次就是這種設(shè)計(jì)的風(fēng)格也大大的影響了數(shù)據(jù)的精度召烂。一個(gè)需要12:00點(diǎn)執(zhí)行的任務(wù)可能12:01才執(zhí)行,這樣對(duì)數(shù)據(jù)要求很高的系統(tǒng)有更大的弊端。由此我們可以使用DelayQueue
垄懂。
我們?cè)诰W(wǎng)咖或者網(wǎng)吧上網(wǎng)時(shí)會(huì)用到一個(gè)網(wǎng)吧綜合系統(tǒng),其中有一個(gè)主要功能就是給每一位網(wǎng)民計(jì)時(shí)痛垛,用戶充值一定金額會(huì)有相應(yīng)的上網(wǎng)時(shí)常草慧,這里我們用DelayQueue模擬實(shí)現(xiàn)一下:
用DelayQueue
存儲(chǔ)網(wǎng)民(Wangmin
類),每一個(gè)考生都有自己的名字和完成試卷的時(shí)間匙头,Wangba
線程對(duì)DelayQueue
進(jìn)行監(jiān)控漫谷,從隊(duì)列中取出到時(shí)間的網(wǎng)民執(zhí)行下機(jī)操作。
實(shí)現(xiàn)了Delayed
接口的網(wǎng)民類
public class Wangmin implements Delayed {
private String name;
//身份證
private String id;
//截止時(shí)間
private long endTime;
//定義時(shí)間工具類
private TimeUnit timeUnit = TimeUnit.SECONDS;
public Wangmin(String name,String id,long endTime){
this.name=name;
this.id=id;
this.endTime = endTime;
}
public String getName(){
return this.name;
}
public String getId(){
return this.id;
}
/**
* 用來(lái)判斷是否到了截止時(shí)間
*/
@Override
public long getDelay(TimeUnit unit) {
//return unit.convert(endTime, TimeUnit.MILLISECONDS) - unit.convert(System.currentTimeMillis(), TimeUnit.MILLISECONDS);
return endTime - System.currentTimeMillis();
}
/**
* 相互批較排序用
*/
@Override
public int compareTo(Delayed delayed) {
Wangmin w = (Wangmin)delayed;
return this.getDelay(this.timeUnit) - w.getDelay(this.timeUnit) > 0 ? 1:0;
}
}
網(wǎng)吧類
public class WangBa implements Runnable {
private DelayQueue<Wangmin> queue = new DelayQueue<Wangmin>();
public boolean yingye =true;
/**
* 上機(jī)
*/
public void shangji(String name,String id,int money){
Wangmin man = new Wangmin(name, id, 1000 * money + System.currentTimeMillis());
System.out.println("網(wǎng)名"+man.getName()+" 身份證"+man.getId()+"交錢"+money+"塊,開始上機(jī)...");
this.queue.add(man);
}
// 下機(jī)
public void xiaji(Wangmin man){
System.out.println("網(wǎng)名"+man.getName()+" 身份證"+man.getId()+"時(shí)間到下機(jī)...");
}
@Override
public void run() {
while(yingye){
try {
Wangmin man = queue.take();
xiaji(man);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String args[]){
try{
System.out.println("網(wǎng)吧開始營(yíng)業(yè)");
WangBa siyu = new WangBa();
Thread shangwang = new Thread(siyu);
shangwang.start();
siyu.shangji("路人甲", "123", 1);
siyu.shangji("路人乙", "234", 10);
siyu.shangji("路人丙", "345", 5);
}
catch(Exception e){
e.printStackTrace();
}
}
}
源碼分析
首先看一下DlayedQueue
源碼
public class DelayQueue<E extends Delayed> extends AbstractQueue<E>
implements BlockingQueue<E> {
private final transient ReentrantLock lock = new ReentrantLock();
private final PriorityQueue<E> q = new PriorityQueue<E>();
// ...
}
這是一小部分源碼蹂析,從這段源碼可以看出舔示,DelayedQueue中處理的是實(shí)現(xiàn)Delayed接口的任務(wù),DelayedQueue使用lock來(lái)實(shí)現(xiàn)線程同步电抚,使用PriorityQueue來(lái)管理任務(wù)惕稻。那么Delayed接口是什么呢?
public interface Delayed extends Comparable<Delayed> {
long getDelay(TimeUnit unit);
}
這是Delayed
接口的官方注釋蝙叛,意思是:一個(gè)混合風(fēng)格的接口俺祠,為創(chuàng)建給定延遲的任務(wù)。(翻譯的不太好借帘,請(qǐng)糾正)蜘渣;其中有兩個(gè)重要的方法compareTo和getDelay,第一個(gè)是比較兩個(gè)任務(wù)的延遲時(shí)間進(jìn)行排序肺然,第二個(gè)方法用來(lái)獲取延遲時(shí)間蔫缸。
priorityQueue
是一種優(yōu)先級(jí)隊(duì)列,這里優(yōu)先級(jí)就是延遲時(shí)間际起,也就是說(shuō)進(jìn)入隊(duì)列的任務(wù)安裝優(yōu)先級(jí)進(jìn)行排序拾碌,延遲時(shí)間最短的在隊(duì)列前面,先被處理街望,也就是說(shuō)倦沧,每次從隊(duì)列中取出的任務(wù)都將是到期的任務(wù)。比如我們實(shí)現(xiàn)一個(gè)緩存它匕,當(dāng)某個(gè)key-value對(duì)超期了展融,我們就可以從隊(duì)列前取出,然后進(jìn)行銷毀操作。
這里有一個(gè)實(shí)現(xiàn)緩存的例子告希,鏈接如下:
http://www.cnblogs.com/jobs/archive/2007/04/27/730255.html