DelayQueue 底层原理和应用详解

线程安全的、无界(写不阻塞)、阻塞、延迟队列

(源码)线程安全的(使用ReentrantLock)无界:
 // 添加元素的方法
 public boolean offer(E e) {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            q.offer(e);
            if (q.peek() == e) {
                leader = null;D
                available.signal();
            }
            return true;
        } finally {
            lock.unlock();
        }
    }
(源码)无界(添加元素使用的是PriorityQueue类中的offer,写不阻塞):
public boolean offer(E e) {
        if (e == null)
            throw new NullPointerException();
        modCount++;
        int i = size;
        if (i >= queue.length)
            grow(i + 1);
        size = i + 1;
        if (i == 0)
            queue[0] = e;
        else
            siftUp(i, e);
        return true;
    }
(源码)阻塞队列,如果peek获取不到数据,available.await()会进入阻塞状态
 public E take() throws InterruptedException {
        final ReentrantLock lock = this.lock;
        lock.lockInterruptibly();
        try {
            for (;;) {
                E first = q.peek();
                if (first == null)
                    available.await();
                else {
                    long delay = first.getDelay(NANOSECONDS);
                    if (delay <= 0)
                        return q.poll();
                    first = null; // don't retain ref while waiting
                    if (leader != null)
                        available.await();
                    else {
                        Thread thisThread = Thread.currentThread();
                        leader = thisThread;
                        try {
                            available.awaitNanos(delay);
                        } finally {
                            if (leader == thisThread)
                                leader = null;
                        }
                    }
                }
            }
        } finally {
            if (leader == null && q.peek() != null)
                available.signal();
            lock.unlock();
        }
    }
延迟队列,使用DelayQueue,必须实现Delayed接口,实现的接口中有两个参数:延迟时间,优先级规则,take方法会根据规则按照优先级执行(源码)
public class DelayQueue<E extends Delayed> extends AbstractQueue<E>
/**
 * 优先级规则:两个任务比较,时间短的优先执行
 */
@Override
public int compareTo(Delayed o) {
    long f = this.getDelay(TimeUnit.MILLISECONDS) - o.getDelay(TimeUnit.MILLISECONDS);
    return (int) f;
}
示例
public class T03_DelayQueue {

	public static void main(String[] args) throws InterruptedException {
		
		BlockingQueue<DelayTask> q = new DelayQueue();
		
		Thread thread1 = new Thread(()->{
			System.out.println("thread1");
		},"线程1");
		
		Thread thread2 = new Thread(()->{
			System.out.println("thread2");
		},"线程2");
		
		DelayTask t1 = new DelayTask(1000,thread2);
		DelayTask t2 = new DelayTask(3000,thread1);
		
		q.offer(t1);
		q.offer(t2);
		for (int i = 0; i < 2; i++) {
			DelayTask take = q.take();
			// 开启线程,执行任务
			take.data.start(); 
			System.out.println(take.toString());
		}
	}
}
class DelayTask implements Delayed{
	long delayTime; // 延迟时间
	long expire; // 过期时间
	Thread data;
	
	public DelayTask(long delayTime,Thread data) {
		this.delayTime = delayTime;
		this.data = data;
		// 过期时间 = 当前时间 + 延迟时间
		this.expire = System.currentTimeMillis() + delayTime;
	}
	/**
	 * 优先级规则:两个任务比较,时间短的优先执行
	 */
	@Override
	public int compareTo(Delayed o) {
		long f = this.getDelay(TimeUnit.MILLISECONDS) - o.getDelay(TimeUnit.MILLISECONDS);
		return (int) f;
	}
	/**
	 * 剩余时间 = 到期时间 - 当前时间
	 */
	@Override
	public long getDelay(TimeUnit unit) {
		return unit.convert(this.expire - System.currentTimeMillis(), TimeUnit.MILLISECONDS);
	}
	@Override
	public String toString() {
		return "线程:"+data.getName()+"执行;延迟时间为:"+ delayTime+";";
	}
	
}
应用场景

1,程序中按照时间顺序执行计划的调度任务,例如数据的归集,首先采集的数据归集到小时表,然后归集到天表,然后月表、年表。

2,从A、B两个系统获取数据,B系统中的数据依赖A系统,这种情况下可以使用DelayQueue队列使用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值