阻塞队列BlockingQueue(三)--DelayQueue

DelayQueue

支持延时获取元素的无界阻塞队列
内部采用PriorityQueue与ReentrantLock实现。

public class DelayQueue<E extends Delayed> extends AbstractQueue<E>
    implements BlockingQueue<E> {

    private transient  final ReentrantLock lock = new ReentrantLock();
    private transient  final Condition available = lock.newCondition();
    private final PriorityQueue<E> q = new PriorityQueue<E>();
    ...
}

队列中元素必须实现Delayed接口,Delayed接口又继承了Comparable接口,原因在于DelayQueue内部元素需要排序,一般情况按过期时间优先级排序。

public interface Delayed extends Comparable<Delayed> {	
    long getDelay(TimeUnit unit);
}

应用场景

  • 缓存系统的设计:可以用DelayQueue保存缓存元素的有效期,使用一个线程循环查询DelayQueue,一旦能从DelayQueue中获取元素时,表示缓存有效期到了。
  • 定时任务调度:使用DelayQueue保存当天将会执行的任务和执行时间,一旦从DelayQueue中获取到任务就开始执行,比如TimerQueue就是使用DelayQueue实现的。

实现Delayed接口

第一步:在对象创建的时候,初始化基本数据。使用time记录当前对象延迟到什么时候可以使用,使用sequenceNumber来标识元素在队列中的先后顺序。

private static final AtomicLong sequencer = new AtomicLong(0);
ScheduledFutureTask(Runnable r, V result, long ns, long period) {
	super(r, result);
	this.time = ns;
	this.period = period;
	this.sequenceNumber = sequencer.getAndIncrement();
}

第二步:实现(Delayed 接口的)getDelay方法返回当前元素还需要延时多长时间,单位是纳秒。

public long getDelay(TimeUnit unit) {
	return unit.convert(time - now(), TimeUnit.NANOSECONDS);
}

第三步:如何实现compareTo方法来指定元素的顺序。例如,让延时时间最长的放在队列的末尾。
compareTo方法实现

如何实现延时阻塞队列

当消费者从队列里获取元素时,如果元素没有达到延时时间,就阻塞当前线程。
实现延时阻塞队列

leader变量是一个等待获取队列头部元素的线程。

  • 如果leader!=null,表示已经有线程在等待获取队列的头元素。所以,使用await()方法让当前线程等待信号。
  • 如果leader==null,则把当前线程设置成leader,并使用awaitNanos()方法让当前线程等待接收信号或等待delay时间。

猜你喜欢

转载自blog.csdn.net/eluanshi12/article/details/85122718