一、背景
项目中经常会用到类似一些需要延迟执行的功能,比如缓存。java提供了DelayQueue来很轻松的实现这种功能。Delayed接口中的getDelay方法返回值小于等于0的时候,表示时间到达,可以从DelayQueue中通过take()方法取的到期的对象。到期对象是实现了Delayed的类。
二、代码实战
下面来模拟缓存失效的例子:
启动一个生产者线程,添加4个DelayedItem到DelayQueue队列。启动一个消费者线程从DelayQueue中获取已经到期的DelayedItem。为了看的比较明显一点,这里启动一个计数线程来模拟时钟。每个DelayedItem都有一个固定的失效时间removeTime,当getDelay方法返回值小于等于0的时候,表示有任务到达期限,这里用removeTime-count表示。从运行结果来看,当count值与removeTime值相等时,消费线程将会取得对象,若未到达期限,则消费线程一直阻塞。
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.DelayQueue;
import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;
public class DelayQueueTest {
private static DelayQueue delayQueue = new DelayQueue();
private static long count = 0L;
private static final int taskNum = 4;
public static void main(String[] args) throws InterruptedException {
Object num = new Object();
final DelayQueueTest delayQueueTest = new DelayQueueTest();
new Thread(new Runnable() {
public void run() {
try {
delayQueueTest.producer();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
while(true) {
if(delayQueue.size()==taskNum) {
break;
}
}
new Thread(new Runnable() {
public void run() {
try {
delayQueueTest.consumer();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
new Thread(new Runnable() {
public void run() {
try {
delayQueueTest.count();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
private void count() throws InterruptedException {
while(true) {
Thread.sleep(1000);
count++;
System.out.println("时间值="+count);
if(taskNum==count) {
break;
}
}
}
private void producer() throws InterruptedException {
for(int i=0; i<taskNum; i++) {
DelayedItem temp = new DelayedItem(i+"",i,(i+1));
System.out.println("生产者="+temp);
delayQueue.put(temp);
}
}
private void consumer() throws InterruptedException {
while(true) {
System.out.println("消费者="+delayQueue.take());
count = 0;
}
}
static class DelayedItem<T> implements Delayed{
private String key;
private T item;
private long liveTime;
private long removeTime;
public DelayedItem(String key,T item,long liveTime) {
this.key = key;
this.item = item;
this.liveTime = liveTime;
this.removeTime = liveTime;
}
/**
* 当返回值小于等于0时则缓存时间到达,take将取出元素
* @param unit
* @return
*/
public long getDelay(TimeUnit unit) {
return removeTime-count;
}
public int compareTo(Delayed o) {
if(o instanceof DelayedItem) {
//已经在队列中存在的对象
DelayedItem<T> tmpDelayedItem = (DelayedItem<T>)o;
//System.out.println("比较对象==="+tmpDelayedItem.key+"==="+this.key);
//失效时间越长的排到队尾
if(this.removeTime > tmpDelayedItem.removeTime) {
return 1;
} else if(this.removeTime == tmpDelayedItem.removeTime) {
return 0;
} else {
return -1;
}
}
return -1;
}
@Override
public String toString() {
return "DelayedItem{" +
"key='" + key + '\'' +
", item=" + item +
", liveTime=" + liveTime +
", removeTime=" + removeTime +
'}';
}
}
}
运行结果:
生产者=DelayedItem{key='0', item=0, liveTime=1, removeTime=1}
生产者=DelayedItem{key='1', item=1, liveTime=2, removeTime=2}
生产者=DelayedItem{key='2', item=2, liveTime=3, removeTime=3}
生产者=DelayedItem{key='3', item=3, liveTime=4, removeTime=4}
时间值=1
消费者=DelayedItem{key='0', item=0, liveTime=1, removeTime=1}
时间值=1
时间值=2
消费者=DelayedItem{key='1', item=1, liveTime=2, removeTime=2}
时间值=1
时间值=2
时间值=3
消费者=DelayedItem{key='2', item=2, liveTime=3, removeTime=3}
时间值=1
时间值=2
时间值=3
时间值=4
消费者=DelayedItem{key='3', item=3, liveTime=4, removeTime=4}