java 中線程協(xié)作

線程協(xié)作

多線程協(xié)作的典型場景,生產(chǎn)者消費(fèi)者模型病游。JAVA 中提供的線程阻塞和線程喚醒 Api

被棄用的 suspend 和 resume

作用:通過 suspend 掛起目標(biāo)線程,通過 resume 喚醒線程改橘。

代碼演示:

public class Demo6 {

    public static Object baozi;

    // 正常的 suspend  resume
    public void suspendResumeTest() throws InterruptedException{
        // 啟動線程
        Thread consumerThread = new Thread(() -> {
            // 沒有包子 則等待
            if (baozi == null) {
                System.out.println("1, 進(jìn)入等待");
                Thread.currentThread().suspend();
            }
            // 買到包子
            System.out.println("2, 買到包子了");
        });

        // 啟動進(jìn)程
        consumerThread.start();
        // 主進(jìn)程休眠3秒飞主,讓消費(fèi)進(jìn)程進(jìn)入掛起
        Thread.sleep(3000);

        // 生產(chǎn)包子碌识,通知消費(fèi)進(jìn)程
        baozi = new Object();

        consumerThread.resume();

        System.out.println("3, 通知消費(fèi)者");
    }

    public static void main(String[] args) throws Exception{
        new Demo6().suspendResumeTest();
    }

}

問題 :

  • 不會釋放鎖
/** 死鎖的suspend/resume筏餐。 suspend并不會像wait一樣釋放鎖魁瞪,故此容易寫出死鎖代碼 */
    public void suspendResumeDeadLockTest() throws Exception {
        // 啟動線程
        Thread consumerThread = new Thread(() -> {
            if (baozidian == null) { // 如果沒包子导俘,則進(jìn)入等待
                System.out.println("1剔蹋、進(jìn)入等待");
                // 當(dāng)前線程拿到鎖泣崩,然后掛起
                synchronized (this) {
                    Thread.currentThread().suspend();
                }
            }
            System.out.println("2律想、買到包子,回家");
        });
        consumerThread.start();
        // 3秒之后著洼,生產(chǎn)一個包子
        Thread.sleep(3000L);
        baozidian = new Object();
        // 爭取到鎖以后而叼,再恢復(fù)consumerThread
        synchronized (this) {
            consumerThread.resume();
        }
        System.out.println("3葵陵、通知消費(fèi)者");
    }

  • 掛起必須在通知前
/** 導(dǎo)致程序永久掛起的suspend/resume */
    public void suspendResumeDeadLockTest2() throws Exception {
        // 啟動線程
        Thread consumerThread = new Thread(() -> {
            if (baozidian == null) {
                System.out.println("1、沒包子娇钱,進(jìn)入等待");
                try { // 為這個線程加上一點(diǎn)延時
                    Thread.sleep(5000L);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                // 這里的掛起執(zhí)行在resume后面
                Thread.currentThread().suspend();
            }
            System.out.println("2文搂、買到包子,回家");
        });
        consumerThread.start();
        // 3秒之后笔喉,生產(chǎn)一個包子
        Thread.sleep(3000L);
        baozidian = new Object();
        consumerThread.resume();
        System.out.println("3常挚、通知消費(fèi)者");
        consumerThread.join();
    }

wait notify

wait 會讓當(dāng)前線程等待稽物,加入該對象的等待集合中,并且釋放當(dāng)前持有的對象鎖

notify/notityAll 用于h喚醒一個或所有等待對象鎖的線程

    /** 正常的wait/notify */
    public void waitNotifyTest() throws Exception {
        // 啟動線程
        new Thread(() -> {
            if (baozidian == null) { // 如果沒包子秧倾,則進(jìn)入等待
                synchronized (this) {
                    try {
                        System.out.println("1、進(jìn)入等待");
                        this.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
            System.out.println("2农猬、買到包子斤葱,回家");
        }).start();
        // 3秒之后,生產(chǎn)一個包子
        Thread.sleep(3000L);
        baozidian = new Object();
        synchronized (this) {
            this.notifyAll();
            System.out.println("3料身、通知消費(fèi)者");
        }
    }

問題 :

  • 掛起必須在通知前
/** 會導(dǎo)致程序永久等待的wait/notify */
    public void waitNotifyDeadLockTest() throws Exception {
        // 啟動線程
        new Thread(() -> {
            if (baozidian == null) { // 如果沒包子芹血,則進(jìn)入等待
                try {
                    Thread.sleep(5000L);
                } catch (InterruptedException e1) {
                    e1.printStackTrace();
                }
                synchronized (this) {
                    try {
                        System.out.println("1幔烛、進(jìn)入等待");
                        this.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
            System.out.println("2饿悬、買到包子聚霜,回家");
        }).start();
        // 3秒之后,生產(chǎn)一個包子
        Thread.sleep(3000L);
        baozidian = new Object();
        synchronized (this) {
            this.notifyAll();
            System.out.println("3傲宜、通知消費(fèi)者");
        }
    }

park unpark

park 等待許可函卒,unpark 拿到許可,多次調(diào)用 unpark 之后虱咧,再調(diào)用park腕巡,線程會執(zhí)行血筑,但是 park 只有一次有效豺总,不能疊加喻喳,也就是 拿到的令牌 只能喚醒一次,下次 park 繼續(xù)等待表伦。

/** 正常的park/unpark */
    public void parkUnparkTest() throws Exception {
        // 啟動線程
        Thread consumerThread = new Thread(() -> {
            if (baozidian == null) { // 如果沒包子鳄哭,則進(jìn)入等待
                System.out.println("1、進(jìn)入等待");
                LockSupport.park();
            }
            System.out.println("2妆丘、買到包子飘痛,回家");
        });
        consumerThread.start();
        // 3秒之后容握,生產(chǎn)一個包子
        Thread.sleep(3000L);
        baozidian = new Object();
        LockSupport.unpark(consumerThread);
        System.out.println("3、通知消費(fèi)者");
    }

問題 :

  • 不會釋放鎖
/** 死鎖的park/unpark */
    public void parkUnparkDeadLockTest() throws Exception {
        // 啟動線程
        Thread consumerThread = new Thread(() -> {
            if (baozidian == null) { // 如果沒包子塑猖,則進(jìn)入等待
                System.out.println("1塑陵、進(jìn)入等待");
                // 當(dāng)前線程拿到鎖,然后掛起
                synchronized (this) {
                    LockSupport.park();
                }
            }
            System.out.println("2令花、買到包子兼都,回家");
        });
        consumerThread.start();
        // 3秒之后扮碧,生產(chǎn)一個包子
        Thread.sleep(3000L);
        baozidian = new Object();
        // 爭取到鎖以后慎王,再恢復(fù)consumerThread
        synchronized (this) {
            LockSupport.unpark(consumerThread);
        }
        System.out.println("3赖淤、通知消費(fèi)者");
    }

偽喚醒

使用 if 判斷進(jìn)入等待是錯誤的负芋,官方建議在循環(huán)中檢查等待條件旧蛾,如果不再循環(huán)中檢查锨天,程序就會在沒有滿足條件的情況下推出病袄。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末益缠,一起剝皮案震驚了整個濱河市幅慌,隨后出現(xiàn)的幾起案子轰豆,更是在濱河造成了極大的恐慌,老刑警劉巖祷杈,帶你破解...
    沈念sama閱讀 223,002評論 6 519
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異渗饮,居然都是意外死亡但汞,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,357評論 3 400
  • 文/潘曉璐 我一進(jìn)店門互站,熙熙樓的掌柜王于貴愁眉苦臉地迎上來特占,“玉大人,你說我怎么就攤上這事云茸∈悄浚” “怎么了?”我有些...
    開封第一講書人閱讀 169,787評論 0 365
  • 文/不壞的土叔 我叫張陵标捺,是天一觀的道長懊纳。 經(jīng)常有香客問我,道長亡容,這世上最難降的妖魔是什么嗤疯? 我笑而不...
    開封第一講書人閱讀 60,237評論 1 300
  • 正文 為了忘掉前任屋谭,我火速辦了婚禮悔耘,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己互妓,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,237評論 6 398
  • 文/花漫 我一把揭開白布伏嗜。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪均践。 梳的紋絲不亂的頭發(fā)上或衡,一...
    開封第一講書人閱讀 52,821評論 1 314
  • 那天椒涯,我揣著相機(jī)與錄音祖搓,去河邊找鬼详囤。 笑死,一個胖子當(dāng)著我的面吹牛捌臊,可吹牛的內(nèi)容都是我干的曙寡。 我是一名探鬼主播,決...
    沈念sama閱讀 41,236評論 3 424
  • 文/蒼蘭香墨 我猛地睜開眼滚粟,長吁一口氣:“原來是場噩夢啊……” “哼亚侠!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 40,196評論 0 277
  • 序言:老撾萬榮一對情侶失蹤橄教,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,716評論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,794評論 3 343
  • 正文 我和宋清朗相戀三年火架,在試婚紗的時候發(fā)現(xiàn)自己被綠了骡男。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,928評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡俱笛,死狀恐怖珊豹,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情两嘴,我是刑警寧澤,帶...
    沈念sama閱讀 36,583評論 5 351
  • 正文 年R本政府宣布枉圃,位于F島的核電站,受9級特大地震影響坎穿,放射性物質(zhì)發(fā)生泄漏篮绿。R本人自食惡果不足惜惶凝,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,264評論 3 336
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧寂呛,春花似錦肉津、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,755評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至熟吏,卻和暖如春距糖,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背牵寺。 一陣腳步聲響...
    開封第一講書人閱讀 33,869評論 1 274
  • 我被黑心中介騙來泰國打工悍引, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人帽氓。 一個月前我還...
    沈念sama閱讀 49,378評論 3 379
  • 正文 我出身青樓趣斤,卻偏偏與公主長得像,于是被迫代替她去往敵國和親黎休。 傳聞我的和親對象是個殘疾皇子浓领,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,937評論 2 361

推薦閱讀更多精彩內(nèi)容

  • ??在多線程環(huán)境中玉凯,多個線程之間互相協(xié)作,以達(dá)到高效實(shí)現(xiàn)程序功能的目的镊逝,比如某些多線程程序要求線程執(zhí)行有先后順序壮啊、...
    小胡_鴨閱讀 403評論 0 1
  • ??談到并發(fā)我們就會想到多線程嫉鲸,要想實(shí)現(xiàn)多個線程之間的協(xié)同撑蒜,如:線程執(zhí)行先后順序、獲取某個線程執(zhí)行的結(jié)果等等玄渗。都涉...
    TodoCoder閱讀 543評論 0 4
  • Lock和synchronized的區(qū)別和使用https://blog.csdn.net/ydk888888/ar...
    pluss閱讀 368評論 0 0
  • 線程通信的方法 程序在使用多線程執(zhí)行任務(wù)時座菠,經(jīng)常需要線程之間協(xié)同工作。此時藤树,我們需要了解線程通信的手段浴滴。 線程通信...
    疊最厚的甲閱讀 737評論 0 0
  • 線程通信 線程通信指的是多個線程在運(yùn)行的期間,相互之間的數(shù)據(jù)交互協(xié)作岁钓。 1.通信方式 實(shí)現(xiàn)多個線程直接的協(xié)作升略,涉及...
    JuneWool閱讀 291評論 0 0