Java-多線(xiàn)程-條件隊(duì)列

一、隊(duì)列Queue類(lèi)型

JUC包中隊(duì)列Queue是用于存儲(chǔ)線(xiàn)程任務(wù),常見(jiàn)的Queue類(lèi)型有ArrayBlockingQueue、LinkedBlockingQueue、PriorityBlockingQueue和DelayQueue。

ArrayBlockingQueue

由數(shù)組組成的有界隊(duì)列,隊(duì)列基于數(shù)組實(shí)現(xiàn),容量大小在創(chuàng)建ArrayBlockingQueue對(duì)象時(shí)已定義好,不可擴(kuò)容。

LinkedBlockingQueue

由鏈接節(jié)點(diǎn)組成的可選有界隊(duì)列,隊(duì)列基于數(shù)組實(shí)現(xiàn),容量大小在創(chuàng)建LinkedBlockingQueue對(duì)象時(shí)已定義好,不可擴(kuò)容。

PriorityBlockingQueue

由優(yōu)先級(jí)堆組成的無(wú)界優(yōu)先級(jí)隊(duì)列,內(nèi)部線(xiàn)程是阻塞的,使用必須實(shí)現(xiàn)compareTo方法,這里的無(wú)界是理論上的。

DelayQueue

由優(yōu)先級(jí)堆支持的、基于時(shí)間的調(diào)度隊(duì)列,由優(yōu)先級(jí)堆支持的、基于時(shí)間的調(diào)度隊(duì)列,內(nèi)部基于無(wú)界隊(duì)列PriorityQueue實(shí)現(xiàn),而無(wú)界隊(duì)列基于數(shù)組的擴(kuò)容實(shí)現(xiàn)。入隊(duì)的對(duì)象必須要實(shí)現(xiàn)Delayed接口。

public static void main(String[] args) {
    DelayQueue<MovieTiket> delayQueue = new DelayQueue<MovieTiket>();
    MovieTiket tiket = new MovieTiket("電影票0",10000);
    delayQueue.put(tiket);
    MovieTiket tiket1 = new MovieTiket("電影票1",5000);
    delayQueue.put(tiket1);
    MovieTiket tiket2 = new MovieTiket("電影票2",8000);
    delayQueue.put(tiket2);
    System.out.println("message:--->入隊(duì)完畢");

    while( delayQueue.size() > 0 ){
        try {
            tiket = delayQueue.take();
            System.out.println("電影票出隊(duì):"+tiket.getMsg());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

public class MovieTiket implements Delayed {
    //延遲時(shí)間
    private final long delay;
    //到期時(shí)間
    private final long expire;
    //數(shù)據(jù)
    private final String msg;
    //創(chuàng)建時(shí)間
    private final long now;

    public MovieTiket(String msg , long delay) {
        this.delay = delay;
        this.msg = msg;
        expire = System.currentTimeMillis() + delay;    //到期時(shí)間 = 當(dāng)前時(shí)間+延遲時(shí)間
        now = System.currentTimeMillis();
    }

    /**
     * 用于延遲隊(duì)列內(nèi)部比較排序  當(dāng)前時(shí)間的延遲時(shí)間 - 比較對(duì)象的延遲時(shí)間
     * 越早過(guò)期的時(shí)間在隊(duì)列中越靠前
     * @param delayed
     * @return
     */
    public int compareTo(Delayed delayed) {
        return (int) (this.getDelay(TimeUnit.MILLISECONDS)
            - delayed.getDelay(TimeUnit.MILLISECONDS));
    }
}

二、Condition隊(duì)列

BlockingQueue底層都是基于ReentrantLock 與 Condition隊(duì)列實(shí)現(xiàn)的,這也是Condition隊(duì)列只能在獨(dú)占模式下使用的原因。
多線(xiàn)程下的BlockingQueue是怎樣操作的?

image.png

若BlockingQueue初始容量為1,T1 T2 同時(shí)操作BlockingQueue,T1不斷往BlockingQueue放,T2不斷從BlockingQueue 取。T1 在放完第一次后,BlockingQueue已滿(mǎn),無(wú)法繼續(xù)放了,T1阻塞,T2喚醒,直到BlockingQueue容量為0;T2從BlockingQueue取出,取完第一次后,BlockingQueue為空,無(wú)法繼續(xù)取了,T2阻塞,T1喚醒,直到BlockingQueue容量為1。
條件關(guān)鍵:BlockingQueue的容量。

image.png

BlockingQueue的創(chuàng)建會(huì)創(chuàng)建一個(gè)ReentrantLock、兩個(gè)隊(duì)列(NotFull與NotEmpty)。

public ArrayBlockingQueue(int capacity, boolean fair) {
    if (capacity <= 0)
        throw new IllegalArgumentException();
    this.items = new Object[capacity];
    lock = new ReentrantLock(fair);
    notEmpty = lock.newCondition();
    notFull =  lock.newCondition();
}

ReentrantLock中用于多線(xiàn)程的同步操作,NotFull與NotEmpty用于存儲(chǔ)不同條件的線(xiàn)程任務(wù)。ArrayBlockingQueue的put 和 take操作都需要配合ReentrantLock的使用,只有線(xiàn)程獲取到鎖的線(xiàn)程才能執(zhí)行put 和 take操作。
注意1:BlockingQueue put操作是通過(guò)獲取ReentrantLock鎖,進(jìn)入條件隊(duì)列而不是CLH同步隊(duì)列,同時(shí)線(xiàn)程會(huì)調(diào)用await方法進(jìn)入阻塞狀態(tài)。
注意2:條件隊(duì)列中阻塞線(xiàn)程不會(huì)被喚醒,只有把條件隊(duì)列中的線(xiàn)程移到CLH同步隊(duì)列中才會(huì)被喚醒。

image.png

三、HashMap線(xiàn)程不安全

死鎖

Java 1.7 HashMap會(huì)產(chǎn)生死鎖,其數(shù)據(jù)結(jié)構(gòu)為數(shù)組+鏈表。在多線(xiàn)程場(chǎng)景下,擴(kuò)容期間存在節(jié)點(diǎn)位置互換指針引用的問(wèn)題有可能導(dǎo)致閉環(huán),主要原因還是鏈表中節(jié)點(diǎn)在擴(kuò)容的時(shí)候位置發(fā)生了變化。
Java 1.8 HashMap后不會(huì)產(chǎn)生死鎖,其數(shù)據(jù)結(jié)構(gòu)為數(shù)組+紅黑樹(shù)。

數(shù)據(jù)丟失

HashMap的put操作在多線(xiàn)程下有可能產(chǎn)生相同的hashcode,從而造成數(shù)據(jù)覆蓋,進(jìn)而造成數(shù)據(jù)丟失。Java 1.7 1.8 HashMap都會(huì)產(chǎn)生這樣的問(wèn)題。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容