ScheduleThreadPoolExecutor源码分析(二)

DelayedWorkQueue:

       DelayedWorkQueue实现了BlockingQueue接口,因此其可以作为线程池的任务队列。BlockingQueue的主要属性有以下几个:

  • private RunnableScheduledFuture[] queue:作为最小堆的实现数组,主要存储ScheduledFutureTask任务列表。
  • private final ReentrantLock lock:可重入锁,保证队列数据多线程下的一致性。
  • private int size = 0:队列中任务总数
  • private Thread leader = null:主要是为了尽量减少队列头任务执行的时间,这个字段将在tack()函数中具体讲解其用法。
  • private final Condition available = lock.newCondition():锁条件变量。

       DelayedWorkQueue最主要的两个方法就是take()和offer()方法。offer()方法是向队列里新增一个任务,take是从延迟队列中取出当前需要执行的任务。

    public boolean offer(Runnable x) {
        if (x == null)
            throw new NullPointerException();
        RunnableScheduledFuture e = (RunnableScheduledFuture)x;
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            int i = size;
            if (i >= queue.length)
                //队列满时,扩容
                grow();
            size = i + 1;
            if (i == 0) {
                queue[0] = e;
                setIndex(e, 0);
            } else {
                //将新加入的任务按照最小堆排序规则进行排序
                siftUp(i, e);
            }
            //当队列只有一个元素时,将leader置为null,并发送消息唤醒take或offer操作
            if (queue[0] == e) {
                leader = null;
                available.signal();
            }
        } finally {
            lock.unlock();
        }
        return true;
    }

       上述为offer操作,用于向队列中插入任务,所有插入的准则都是按照最小堆准则,保证堆顶元素为最先需要执行的任务。

    public RunnableScheduledFuture take() throws InterruptedException {
        final ReentrantLock lock = this.lock;
        lock.lockInterruptibly();
        try {
            for (;;) {
                //获取堆顶元素,也就是需要现在执行的任务
                RunnableScheduledFuture first = queue[0];
                if (first == null)
                    //如果队列中没有元素则等待,对应offer()中的available.signal();
                    available.await();
                else {
                    long delay = first.getDelay(TimeUnit.NANOSECONDS);
                    if (delay <= 0)
                        return finishPoll(first);
                    else if (leader != null)
                        //如果leader不为null说明该线程正在执行其他操作(例如offer)
                        available.await();
                    else {
                        Thread thisThread = Thread.currentThread();
                        //将leader置为当前线程
                        leader = thisThread;
                        try {
                            //等待直到该线程需要执行的时间点,在下一个循环中获取当前任务
                            available.awaitNanos(delay);
                        } finally {
                            //无论什么操作,在返回前必须将leader置为null
                            if (leader == thisThread)
                                leader = null;
                        }
                    }
                }
            }
        } finally {
            if (leader == null && queue[0] != null)
                available.signal();
            lock.unlock();
        }
    }
posted @ 2016-07-18 19:37  星、落  阅读(175)  评论(0编辑  收藏  举报