java.concurrent包之DelayQueue源码分析

延迟队列在java并发包中 其源码来说相对较简单,下面就让我们来分析一下延迟队列的实现,以下是基于jdk1.8实现的DelayQueue的主干代码

 

package java.util.concurrent;
import java.util.concurrent.locks.*;
import java.util.*;


public class DelayQueue<E extends Delayed> extends AbstractQueue<E>
    implements BlockingQueue<E> {
     //锁
    private transient final ReentrantLock lock = new ReentrantLock(); 

   //优先级队列 其目的是使最小执行的位于队列队首 

  private final PriorityQueue<E> q = new PriorityQueue<E>();
    
   //leader 作用我在最后会解释
    private Thread leader = null;

    //判断条件,不明白的去百度下lock锁中condition的用法,
    private final Condition available = lock.newCondition();

    public DelayQueue() {}

   
    public DelayQueue(Collection<? extends E> c) {
        this.addAll(c);
    }

    public boolean add(E e) {
        return offer(e); 
    }


    public boolean offer(E e) {
        final ReentrantLock lock = this.lock; //加锁
        lock.lock();
        try {
            q.offer(e); //入队列

    //相等说明,加入的优先级更高,需要重新设置leader 这部分看不懂,请先看完下面回过头来看
            if (q.peek() == e) { 
                leader = null; //leader置为空,

                available.signal();  //唤醒等待的线程
            }
            return true;
        } finally {
            lock.unlock();
        }
    }

  
    public void put(E e) {
        offer(e);
    }

    public boolean offer(E e, long timeout, TimeUnit unit) {
        return offer(e);
    }

   //出队列
    public E poll() {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            E first = q.peek(); //得到对头元素
             //为空,或者还没到执行时间 返回空
            if (first == null || first.getDelay(TimeUnit.NANOSECONDS) > 0)//为空
                return null;
            else
                return q.poll(); //否则 取出对头元素
        } finally {
            lock.unlock();
        }
    }

    /**
     * Retrieves and removes the head of this queue, waiting if necessary
     * until an element with an expired delay is available on this queue.
     *
     * @return the head of this queue
     * @throws InterruptedException {@inheritDoc}
     */
    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(TimeUnit.NANOSECONDS);
                    if (delay <= 0) //小于或等于0 说明到期
                        return q.poll(); //返回
                    else if (leader != null) //不为空
                        available.await(); //等待
                    else { 
                       //为空进入这里,将当前线程赋值给leader
                        Thread thisThread = Thread.currentThread();
                        leader = thisThread;
                        try {
                            available.awaitNanos(delay); //等待delay时间后,重新竞争锁
                        } finally {
                            if (leader == thisThread) //等于当前线程,有可能leader改变
                                                       //如新加入的元素位于队首就有可能
                                leader = null; //置为空
                        }
                    }
                }
            }
        } finally {
            if (leader == null && q.peek() != null)
                available.signal(); //
            lock.unlock();
        }
    }

这里解释下leader的作用,leader表示正在等待队首任务的线程,因为任务有一个线程执行过就够了,在多线程的环境下,如果没有leader,多个线程并发执行后,假设同时调用 available.awaitNanos(delay)后,
导致同一时间后同时苏醒,多个线程并发竞争锁,加剧了锁的竞争和cpu的开销,为此这里使用leader做个优化,表明队首任务已近有线程在等待,其他线程直接await()无限等待,直到被唤醒即可。即前面在offer时如果加入后的元素位于队首,leader需要置空,并唤醒线程


    /**
     * Retrieves and removes the head of this queue, waiting if necessary
     * until an element with an expired delay is available on this queue,
     * or the specified wait time expires.
     *
     * @return the head of this queue, or <tt>null</tt> if the
     *         specified waiting time elapses before an element with
     *         an expired delay becomes available
     * @throws InterruptedException {@inheritDoc}
     */
//与take差不多,只不过带一个超时时间,大部分是一样的这里就不做解释了
    public E poll(long timeout, TimeUnit unit) throws InterruptedException {
        long nanos = unit.toNanos(timeout);
        final ReentrantLock lock = this.lock;
        lock.lockInterruptibly();
        try {
            for (;;) {
                E first = q.peek();
                if (first == null) {
                    if (nanos <= 0)
                        return null;
                    else
                        nanos = available.awaitNanos(nanos);
                } else {
                    long delay = first.getDelay(TimeUnit.NANOSECONDS);
                    if (delay <= 0)
                        return q.poll();
                    if (nanos <= 0)
                        return null;
                    if (nanos < delay || leader != null)
                        nanos = available.awaitNanos(nanos);
                    else {
                        Thread thisThread = Thread.currentThread();
                        leader = thisThread;
                        try {
                            long timeLeft = available.awaitNanos(delay);
                            nanos -= delay - timeLeft;
                        } finally {
                            if (leader == thisThread)
                                leader = null;
                        }
                    }
                }
            }
        } finally {
            if (leader == null && q.peek() != null)
                available.signal();
            lock.unlock();
        }
    }

    /**
     * Retrieves, but does not remove, the head of this queue, or
     * returns <tt>null</tt> if this queue is empty.  Unlike
     * <tt>poll</tt>, if no expired elements are available in the queue,
     * this method returns the element that will expire next,
     * if one exists.
     *
     * @return the head of this queue, or <tt>null</tt> if this
     *         queue is empty.
     */
    public E peek() {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            return q.peek();
        } finally {
            lock.unlock();
        }
    }

    public int size() {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            return q.size();
        } finally {
            lock.unlock();
        }
    }

   

   

    /**
     * Atomically removes all of the elements from this delay queue.
     * The queue will be empty after this call returns.
     * Elements with an unexpired delay are not waited for; they are
     * simply discarded from the queue.
     */
    public void clear() {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            q.clear();
        } finally {
            lock.unlock();
        }
    }

   
   
    
  
   

    /**
     * Removes a single instance of the specified element from this
     * queue, if it is present, whether or not it has expired.
     */
    public boolean remove(Object o) {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            return q.remove(o);
        } finally {
            lock.unlock();
        }
    }

    
  

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值