Java 併發工具包-BlockingQueue-DelayQueue

DelayQueue 延時隊列,延時一段時間後執行的隊列,根據這個特性,可以應用在
1 緩存的生成及自動過期刪除
2 任務超時處理

其存儲元素必須繼承實現Delayed接口

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

可見 我們需要實現兩個方法
1 getDelay 獲取延遲時間
2 compareTo 內部隊列的排序

我們先來看下 入隊、出隊

 public boolean add(E e) {
        return offer(e);
}
public void put(E e) {
        offer(e);
}
 public boolean offer(E e) {
 // 兩個作用 
 //1 下面的引用不需要通過this.lock,直接從堆棧獲取引用 效率更高
 //2 防止誤操作
        final ReentrantLock lock = this.lock;
        //獨佔鎖 線程安全
        lock.lock();
        try {
        //這裏的q是PriorityQueue 優先隊列 fifo模式 可以看出DelayQueue 使用的是先進先出的模式,將對象放入隊列中  這裏會調用compareTo進行內部排序
            q.offer(e);
            //獲取當前隊列最頂隊列對象,如果和當前對象相等,說明
            //原先隊列爲空
            if (q.peek() == e) {
                leader = null;
                //插入成功,通知喚醒
                available.signal();
            }
            return true;
        } finally {
        // 釋放鎖
            lock.unlock();
        }
    }
//排序方法
  private void siftUpComparable(int k, E x) {
        Comparable<? super E> key = (Comparable<? super E>) x;
        //循環比較,找到比自己大的 break
        while (k > 0) {
            int parent = (k - 1) >>> 1;
            Object e = queue[parent];

            if (key.compareTo((E) e) >= 0)
                break;
            queue[k] = e;
            k = parent;
        }
        queue[k] = key;
    }

主要看的還是offer方法

//
    public E peek() {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            return q.peek();
        } finally {
            lock.unlock();
        }
    }
    public E poll() {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            E first = q.peek();
            //如果還未過期  則返回null
            if (first == null || first.getDelay(NANOSECONDS) > 0)
                return null;
            else//
                return q.poll();
        } finally {
            lock.unlock();
        }
    }
 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);
                    //如果小於0,已經過時,直接拋出對象返回
                    if (delay <= 0)
                        return q.poll();
                        //對象回收
                    first = null; // don't retain ref while waiting
                    //如果當前leader已經被某線程賦值,則等待
                    if (leader != null)
                        available.await();
                    else {
                        Thread thisThread = Thread.currentThread();
                        //否則賦值leader
                        leader = thisThread;
                        try {
                            //等待delay時間後 喚醒 繼續循環
                            available.awaitNanos(delay);
                        } finally {
                        //leader=null 
                            if (leader == thisThread)
                                leader = null;
                        }
                    }
                }
            }
        } finally {
            //當隊列不爲空,則進行通知,否則不通知
            if (leader == null && q.peek() != null)
                available.signal();
            lock.unlock();
        }
    }
    //he 
     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(NANOSECONDS);
                    if (delay <= 0)
                        return q.poll();
                    if (nanos <= 0)
                        return null;
                    first = null; // don't retain ref while waiting
                    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();
        }
    }

tack 方法貌似多點,不過整過過程還是比較簡單的!
1 循環
2 判斷是否過時
3 等待

    public final long awaitNanos(long nanosTimeout)
                throws InterruptedException {
                //線程是否被打斷  打斷 則拋異常,這裏和lock.lockInterruptibly();對應
            if (Thread.interrupted())
                throw new InterruptedException();
                //通過當前線程 創建節點
            Node node = addConditionWaiter();
            //嘗試是否,並且獲取當前狀態
            int savedState = fullyRelease(node);
            //過期時間
            final long deadline = System.nanoTime() + nanosTimeout;
            int interruptMode = 0;
            //判斷是否需要等待
            while (!isOnSyncQueue(node)) {

                if (nanosTimeout <= 0L) {
                    //插到隊列末尾
                    transferAfterCancelledWait(node);
                    break;
                }

                if (nanosTimeout >= spinForTimeoutThreshold)
                //調用底層 對該線程進行阻塞
                    LockSupport.parkNanos(this, nanosTimeout);
                    //是否打斷
                if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
                    break;

                nanosTimeout = deadline - System.nanoTime();
            }
            if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
                interruptMode = REINTERRUPT;
            if (node.nextWaiter != null)
                unlinkCancelledWaiters();
            if (interruptMode != 0)
                reportInterruptAfterWait(interruptMode);
            return deadline - System.nanoTime();
        }

總結

適用於一段時間後執行的場景,常見於自定義緩存、超時、某段時間後需要處理的業務。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章