1. 程式人生 > >java併發容器——延遲佇列DelayQueue

java併發容器——延遲佇列DelayQueue

延時阻塞佇列DelayQueue是一種特殊的優先順序佇列,它也是無界的,它要求每個元素都實現Delayed介面,該介面的宣告為:

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

Delayed擴充套件了Comparable介面,也就是說,DelayQueue的每個元素都是可比較的,它有一個額外方法getDelay返回一個給定時間單位unit的整數,表示再延遲多長時間,如果小於等於0,表示不再延遲。

DelayQueue也是優先順序佇列,它按元素的延時時間出隊,它的特殊之處在於,只有當元素的延時過期之後才能被從佇列中拿走,也就是說,take方法總是返回第一個過期的元素,如果沒有,則阻塞等待。

DelayQueue可以用於實現定時任務,我們看段簡單的示例程式碼:

public class DelayedQueueDemo {
    private static final AtomicLong taskSequencer = new AtomicLong(0);

    static class DelayedTask implements Delayed {
        private long runTime;
        private long sequence;
        private Runnable task;

        public DelayedTask(int delayedSeconds, Runnable task) {
            this.runTime = System.currentTimeMillis() + delayedSeconds * 1000;
            this.sequence = taskSequencer.getAndIncrement();
            this.task = task;
        }

        @Override
        public int compareTo(Delayed o) {
            if (o == this) {
                return 0;
            }
            if (o instanceof DelayedTask) {
                DelayedTask other = (DelayedTask) o;
                if (runTime < other.runTime) {
                    return -1;
                } else if (runTime > other.runTime) {
                    return 1;
                } else if (sequence < other.sequence) {
                    return -1;
                } else {
                    return 1;
                }
            }
            throw new IllegalArgumentException();
        }

        @Override
        public long getDelay(TimeUnit unit) {
            return unit.convert(runTime - System.currentTimeMillis(),
                    TimeUnit.MICROSECONDS);
        }

        public Runnable getTask() {
            return task;
        }
    }

    public static void main(String[] args) throws InterruptedException {
        DelayQueue<DelayedTask> tasks = new DelayQueue<>();
        tasks.put(new DelayedTask(2, new Runnable() {
            @Override
            public void run() {
                System.out.println("execute delayed task");
            }
        }));

        DelayedTask task = tasks.take();
        task.getTask().run();
    }
}


DelayedTask表示延時任務,只有延時過期後任務才會執行,任務按延時時間排序,延時一樣的按照入隊順序排序。

內部,DelayQueue是基於PriorityQueue實現的,它使用一個鎖ReentrantLock保護所有訪問,使用一個條件available表示頭部是否有元素,當頭部元素的延時未到時,take操作會根據延時計算需睡眠的時間,然後睡眠,如果在此過程中有新的元素入隊,且成為頭部元素,則阻塞睡眠的執行緒會被提前喚醒然後重新檢查。以上是基本思路,DelayQueue的實現有一些優化,以減少不必要的喚醒,具體我們就不探討了。

模擬一個考試的日子,考試時間為120分鐘,30分鐘後才可交卷,當時間到了,或學生都交完捲了考試結束。

這個場景中幾個點需要注意:

  1. 考試時間為120分鐘,30分鐘後才可交卷,初始化考生完成試卷時間最小應為30分鐘
  2. 對於能夠在120分鐘內交卷的考生,如何實現這些考生交卷
  3. 對於120分鐘內沒有完成考試的考生,在120分鐘考試時間到後需要讓他們強制交卷
  4. 在所有的考生都交完卷後,需要將控制執行緒關閉

抽象出兩個類,學生類和老師類,用DelayQueue儲存考生(Student類)。每一個考生都有自己的名字和完成試卷的時間

Teacher執行緒對DelayQueue進行監控,收取完成試卷小於120分鐘的學生的試卷。當考試時間120分鐘到時,teacher執行緒宣佈考試結束,強制DelayQueue中還存在的考生交卷。

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61

相關推薦

java併發容器——延遲佇列DelayQueue

延時阻塞佇列DelayQueue是一種特殊的優先順序佇列,它也是無界的,它要求每個元素都實現Delayed介面,該介面的宣告為: public interface Delayed extends Comparable<Delayed> {     

併發佇列-無界阻塞延遲佇列DelayQueue原理探究

一、前言 DelayQueue佇列中每個元素都有個過期時間,並且佇列是個優先順序佇列,當從佇列獲取元素時候,只有過期元素才會出佇列。 二、 DelayQueue類圖結構 如圖DelayQueue中內部使用的是PriorityQueue存放資料,使用ReentrantLock實現執行緒同步,

Java延遲佇列DelayQueue裡的坑 concurrent.Delayed

使用延遲佇列需要實現Delayed介面 重要的是此介面方法 @Override public long getDelay(TimeUnit unit) { System.err

Java同步佇列(非阻塞佇列與阻塞佇列)——java併發容器

在併發程式設計中,有時候需要使用執行緒安全的佇列。如果要實現一個執行緒安全的佇列有兩種方式:一種是使用阻塞演算法,另一種是使用非阻塞演算法。 使用阻塞演算法的佇列可以用一個鎖(入隊和出隊用同一把鎖)或兩個鎖(入隊和出隊用不同的鎖)等方式來實現。 非阻塞的實現方式則可以使用

Java併發容器詳細介紹

概述         java.util包中的大部分容器都是非執行緒安全的,若要在多執行緒中使用容器,你可以使用Collections提供的包裝函式:synchronizedXXX,將普通容器變成執行緒安全的容器。但該方法僅僅是簡單地給容器使用同步,效率很

Java併發容器:ConcurrentLinkedQueue

轉自:https://blog.csdn.net/chenssy/article/details/74853120 http://cmsblogs.com/ 要實現一個執行緒安全的佇列有兩種方式:阻塞和非阻塞。阻塞佇列無非就是鎖的應用,而非阻塞則是CAS演算法的應用。下面我們就開始一個非

延遲佇列DelayQueue簡單入門

一、DelayQueue是什麼 DelayQueue是一個無界的BlockingQueue,用於放置實現了Delayed介面的物件,其中的物件只能在其到期時才能從佇列中取走。這種佇列是有序的,即隊頭物件的延遲到期時間最長。注意:不能將null元素放置到這種佇列中。 二、Delay

JAVA併發容器:ConcurrentSkipListMap

生活 目標定下來以後就不要去變,只要確定是對的,總可以到達。 二分查詢 二分查詢要求有序性,為了保障可以隨機訪問,因此會把資料儲存在連續的記憶體中,在查詢的時候效率高,但是在增加和刪除時需要大量移動元素以保證有序,所以效率不高。 如果需要快速的二分查詢,又要兼顧刪除增加元素的效率

JAVA併發容器:CopyOnWriteArrayList與CopyOnWriteArraySet

生活 所有的程式設計師都劇作家,而所有計算機都是糟糕的演員。 CopyOnWriteArrayList介紹 還記得學集合的時候,學的第一個集合就是ArrayList.它是一個由陣列實現的集合。因為他對陣列的增刪改和查詢都是不加鎖的,所以它並不是執行緒安全的。 因此,我們會引入到一

JAVA併發容器:JDK1.7 與 1.8 ConcurrentHashMap 區別

生活 為什麼我們總是沒有時間把事情做對,卻有時間做完它? 瞭解ConcurrentHashMap 工作中常用到hashMap,但是HashMap在多執行緒高併發場景下並不是執行緒安全的。 所以引入了ConcurrentHashMap,它是HashMap的執行緒安全版本,採用了分段

java併發包訊息佇列及在開源軟體中的應用

1.BlockingQueue的常用方法 BlockingQueue也是java.util.concurrent下的主要用來控制執行緒同步的工具。 主要的方法是:put、take一對阻塞存取;add、poll一對非阻塞存取。          插入:        1

java 併發容器

解決併發情況下的容器執行緒安全問題的。給多執行緒環境準備一個執行緒安全的容器物件。 執行緒安全的容器物件: Vector, Hashtable。執行緒安全容器物件,都是使用 synchronized 方法實現的。 concurrent 包中的同步容器,大多數是使

JAVA併發容器:為什麼說ConcurrentHashMap是弱一致性的?

ConcurrentHashMap的弱一致性體現在clear、迭代器和get方法,原因在於沒有加鎖。 舉例: 迭代器在遍歷資料的時候是一個Segment一個Segment去遍歷的,如果在遍歷完一個Segment時正好有一個執行緒在剛遍歷完的Segment上插入資料,就會體現出不一致性。 cl

深入剖析java併發之阻塞佇列LinkedBlockingQueue與ArrayBlockingQueue

關聯文章: 深入理解Java型別資訊(Class物件)與反射機制 深入理解Java列舉型別(enum) 深入理解Java註解型別(@Annotation) 深入理解Java類載入器(ClassLoader) 深入理解Java併發之synchronized實現原理

java併發包訊息佇列

訊息佇列常用於有生產者和消費者兩類角色的多執行緒同步場景BlockingQueue也是java.util.concurrent下的主要用來控制執行緒同步的工具。主要的方法是:put、take一對阻塞存取;add、poll一對非阻塞存取。         插入:        

【搞定Java併發程式設計】第21篇:Java併發容器之ConcurrentHashMap詳解

上一篇:讀寫鎖 --- ReentrantReadWriteLock詳解 本文目錄: 1、為什麼要使用ConcurrentHashMap? 2、ConcurrentHashMap的實現 2.1、ConcurrentHashMap中主要的成員變數、成員方法和內部類 2.2、分段鎖的

java併發程式設計——阻塞佇列與非阻塞佇列

ArrayBlockingQueue ArrayBlockingQueue是一個有界阻塞佇列,資料結構基於陣列、使用ReentrantLock、Condition保證併發同步。 所謂阻塞佇列 當佇列滿了,則會對生產執行緒產生阻塞直到有空位可插入; 當佇列

Java併發容器ConcurrentHashMap原理及HashMap死迴圈原因的分析

HashMap是我們最常用的資料結構之一,它方便高效,但遺憾的是,HashMap是執行緒不安全的,在併發環境下,在HashMap的擴容過程中,可能造成散列表的迴圈鎖死。而執行緒安全的HashTable使用了大量Synchronized鎖,導致了效率非常低下。幸運的是,併發程

Java併發程式設計(八):Java併發容器和框架

1. ConcurrentHashMap 1.1 ConcurrentHashMap的優勢 在併發程式設計中使用HashMap可能導致程式死迴圈。而使用執行緒安全的HashTable效率又非 常低下,基於以上兩個原因,便有了ConcurrentHashMap的登場機會。

java併發程式設計條件佇列的喚醒機制探究

bf1,bf2是兩個大小各為3的條件佇列。3將要put進bf1,此時因為bf1已滿而已呼叫wait()方法掛起執行緒,此時若對bf2()執行take()方法並呼叫notifyall()是否會喚醒wait()中的bf1?(對兩個佇列的操作存在於兩個不同的執行緒