国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

《java.util.concurrent 包源碼閱讀》07 LinkedBlockingQueue

2019-11-14 20:50:19
字體:
來源:轉載
供稿:網友
java.util.concurrent 包源碼閱讀》07 LinkedBlockingQueue

這篇文章來說說稍微復雜一些的LinkedBlockingQueue。LinkedBlockingQueue使用一個鏈表來實現,會有一個head和tail分別指向隊列的開始和隊列的結尾。因此LinkedBlockingQueue會有兩把鎖,分別控制這兩個元素,這樣在添加元素和拿走元素的時候就不會有鎖的沖突,因此取走元素操作的是head,而添加元素操作的是tail。

老規矩先看offer方法和poll方法

    public boolean offer(E e) {        if (e == null) throw new NullPointerException();        final AtomicInteger count = this.count;        if (count.get() == capacity)            return false;        int c = -1;        Node<E> node = new Node(e);        final ReentrantLock putLock = this.putLock;        putLock.lock();        try {            if (count.get() < capacity) {                enqueue(node);                c = count.getAndIncrement();                if (c + 1 < capacity)                    notFull.signal();            }        } finally {            putLock.unlock();        }        if (c == 0)            signalNotEmpty();        return c >= 0;    }

可以看到offer方法在添加元素時候僅僅涉及到putLock,但是還是會需要takeLock,看看signalNotEmpty代碼就知道。而poll方法拿走元素的時候涉及到takeLock,也是會需要putLock。參見signalNotFull()。關于signalNotEmpty會在后面講阻塞的時候講到。

    public E poll() {        final AtomicInteger count = this.count;        if (count.get() == 0)            return null;        E x = null;        int c = -1;        final ReentrantLock takeLock = this.takeLock;        takeLock.lock();        try {            if (count.get() > 0) {                x = dequeue();                c = count.getAndDecrement();                if (c > 1)                    notEmpty.signal();            }        } finally {            takeLock.unlock();        }        if (c == capacity)            signalNotFull();        return x;    }

這里順便說說隊列長度的count,因為有兩把鎖存在,所以如果還是像ArrayBlockingQueue一樣使用基本類型的count的話會同時用到兩把鎖,這樣就會很復雜,因此直接使用原子數據類型AtomicInteger來操作count。

接下來談談阻塞的問題,一個BlockingQueue會有兩個Condition:notFull和notEmpty,LinkedBlockingQueue會有兩把鎖,因此這兩個Condition肯定是由這兩個鎖分別創建的,takeLock創建notEmpty,putLock創建notFull。

    /** Lock held by take, poll, etc */    PRivate final ReentrantLock takeLock = new ReentrantLock();    /** Wait queue for waiting takes */    private final Condition notEmpty = takeLock.newCondition();    /** Lock held by put, offer, etc */    private final ReentrantLock putLock = new ReentrantLock();    /** Wait queue for waiting puts */    private final Condition notFull = putLock.newCondition();

接下來看看put方法:

    public void put(E e) throws InterruptedException {        if (e == null) throw new NullPointerException();        // Note: convention in all put/take/etc is to preset local var        // holding count negative to indicate failure unless set.        int c = -1;        Node<E> node = new Node(e);        final ReentrantLock putLock = this.putLock;        final AtomicInteger count = this.count;        putLock.lockInterruptibly();        try {            /*             * Note that count is used in wait guard even though it is             * not protected by lock. This works because count can             * only decrease at this point (all other puts are shut             * out by lock), and we (or some other waiting put) are             * signalled if it ever changes from capacity. Similarly             * for all other uses of count in other wait guards.             */            while (count.get() == capacity) {                notFull.await();            }            enqueue(node);            c = count.getAndIncrement();            if (c + 1 < capacity)                notFull.signal();        } finally {            putLock.unlock();        }        if (c == 0)            signalNotEmpty();    }

其實大體邏輯和ArrayBlockingQueue差不多,也會需要通知notEmpty條件,因為notEmpty條件屬于takeLock,而調用signal方法需要獲取Lock,因此put方法也是用到了另外一個鎖:takeLock。這里有一點會不同,按照道理來說put方法是不需要通知notFull條件的,是由由拿走元素的操作來通知的,但是notFull條件屬于putLock,而拿走元素時,是用了takeLock,因此這里put方法在擁有putLock的情況通知notFull條件,會讓其他添加元素的方法避免過長時間的等待。同理對于take方法來說也通知notEmpty條件。

    public E take() throws InterruptedException {        E x;        int c = -1;        final AtomicInteger count = this.count;        final ReentrantLock takeLock = this.takeLock;        takeLock.lockInterruptibly();        try {            while (count.get() == 0) {                notEmpty.await();            }            x = dequeue();            c = count.getAndDecrement();            if (c > 1)                notEmpty.signal();        } finally {            takeLock.unlock();        }        if (c == capacity)            signalNotFull();        return x;    }

最后說說remove和contains方法,因為需要操作整個鏈表,因此需要同時擁有兩個鎖才能操作。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 霍林郭勒市| 林口县| 德安县| 依兰县| 通化市| 嘉义市| 政和县| 宝清县| 贞丰县| 滁州市| 新密市| 台南县| 锦州市| 福清市| 盈江县| 宣威市| 渭南市| 体育| 株洲县| 宜城市| 措美县| 扶余县| 灵川县| 霍州市| 绥江县| 铅山县| 岑巩县| 普格县| 本溪市| 丰原市| 高雄县| 江华| 德钦县| 保康县| 苏州市| 新民市| 江都市| 缙云县| 枣庄市| 株洲县| 兴山县|