JUC學(xué)習(xí)--一次解決生產(chǎn)者,消費(fèi)者問(wèn)題

生產(chǎn)者鹿寨,消費(fèi)者問(wèn)題本質(zhì)是不同線程都需求臨界區(qū)中的資源新博。為保證線程安全,需要讓線程同步操作脚草。

在Java中赫悄,對(duì)這個(gè)問(wèn)題的實(shí)現(xiàn)可以有兩種方式:

  1. synchronized對(duì)代碼塊同步
    實(shí)現(xiàn)如下
  • 注意將線程和任務(wù)進(jìn)行解耦,單獨(dú)定義資源類
class Data1{
    //資源類馏慨,對(duì)線程和任務(wù)進(jìn)行分離
    private int number=1;

    public synchronized void increment() throws InterruptedException {
        if(number!=0){
            //判斷埂淮,并等待
            wait();
        }
        //業(yè)務(wù)
        System.out.println(Thread.currentThread().getName()+"is running");
        number++;
        //喚醒
        notifyAll();

    }

    public synchronized void decrement() throws InterruptedException {
        if(number!=1){
            //判斷,并等待
            wait();
        }
        //業(yè)務(wù)
        System.out.println(Thread.currentThread().getName()+"is running");
        number--;
        //喚醒
        notifyAll();
    }
}

main方法

public class ProducerConsumer {
    public static void main(String[] args) {
        Data2 data1 = new Data2();

        new Thread(()->{
            for (int i = 1; i<=10; i++){
                data1.increment();
            }
        }, "A").start();

        new Thread(()->{
            for (int i = 1; i<=10; i++){
                data1.decrement();
            }
        }, "B").start();
    }
}
  1. 第二種方式使用JUC包中的ReentrantLock

使用前將synchronized和ReentrantLock簡(jiǎn)單對(duì)比

  • synchronized鎖是隱式的写隶,ReentrantLock顯式調(diào)用倔撞。
  • syn代碼塊中的等待是通過(guò)Object.wait()實(shí)現(xiàn)
  • ReentrantLock提供了等價(jià)的監(jiān)視器對(duì)象Condition
  • Condition.await() -> Object.wait(); Condition.signalAll() -> Object.notifyAll()

所以代碼可以如下實(shí)現(xiàn):

main方法不變

//使用Reentrantlock實(shí)現(xiàn), condition.await()和signal()替換wait(),notifyAll()
class Data2{

    private int number = 1;
    private Lock lock = new ReentrantLock();
    private Condition condition = lock.newCondition();

    public void increment(){
        lock.lock();
        try {
            //判斷等待
            while (number!=0){
                condition.await();
            }
            number++;
            System.out.println(Thread.currentThread().getName()+"is running, Num is "+number);
            condition.signalAll();
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            lock.unlock();
        }

    }

    public void decrement(){
        lock.lock();
        try {
            //判斷等待
            while (number!=1){
                condition.await();
            }
            number--;
            System.out.println(Thread.currentThread().getName()+"is running");
            condition.signalAll();
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }
}
  1. Condition不只是覆蓋原本的Object方法,還可以實(shí)現(xiàn)多個(gè)監(jiān)聽器的指定順序喚醒
  • 只列出資源類的實(shí)現(xiàn)
  • 可以看到每個(gè)線程將調(diào)用的方法均準(zhǔn)備一個(gè)監(jiān)視器用于監(jiān)聽
final class Data3{
    private int number = 1;
    private Lock lock = new ReentrantLock();
    private Condition condition1 = lock.newCondition();
    private Condition condition2 = lock.newCondition();
    private Condition condition3 = lock.newCondition();

    public void print1(){
        lock.lock();
        try {
            //判斷等待
            while (number!=1){
                condition1.await();
            }
            number = 2;
            System.out.println(Thread.currentThread().getName()+"is running, Num is "+number);
            condition2.signal();
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            lock.unlock();
        }

    }

    public void print2(){
        lock.lock();
        try {
            //判斷等待
            while (number!=2){
                condition2.await();
            }
            number = 3;
            System.out.println(Thread.currentThread().getName()+"is running, Num is "+number);
            condition3.signal();
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }
    public void print3(){
        lock.lock();
        try {
            //判斷等待
            while (number!=3){
                condition3.await();
            }
            number = 1;
            System.out.println(Thread.currentThread().getName()+"is running, Num is "+number);
            condition1.signal();
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }

}
  1. 細(xì)節(jié)分享

實(shí)現(xiàn)判斷等待的代碼一定要使用while循環(huán)判斷慕趴,僅使用if會(huì)產(chǎn)生 虛假喚醒

虛假喚醒: (不只一個(gè)生產(chǎn)者或消費(fèi)者)考慮多個(gè)消費(fèi)者線程同時(shí)在判斷處等待痪蝇, 生產(chǎn)者完成生產(chǎn)操作喚醒所有線程,但實(shí)際資源數(shù)小于等待線程數(shù)秩贰,且wait()被喚醒的方法默認(rèn)獲得了鎖霹俺,繼續(xù)向下執(zhí)行消費(fèi)的代碼,那么會(huì)導(dǎo)致錯(cuò)誤的結(jié)果毒费。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末丙唧,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子觅玻,更是在濱河造成了極大的恐慌想际,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,104評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件溪厘,死亡現(xiàn)場(chǎng)離奇詭異胡本,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)畸悬,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,816評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門侧甫,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事披粟≈涠停” “怎么了?”我有些...
    開封第一講書人閱讀 168,697評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵守屉,是天一觀的道長(zhǎng)惑艇。 經(jīng)常有香客問(wèn)我,道長(zhǎng)拇泛,這世上最難降的妖魔是什么滨巴? 我笑而不...
    開封第一講書人閱讀 59,836評(píng)論 1 298
  • 正文 為了忘掉前任,我火速辦了婚禮俺叭,結(jié)果婚禮上恭取,老公的妹妹穿的比我還像新娘。我一直安慰自己绪颖,他們只是感情好秽荤,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,851評(píng)論 6 397
  • 文/花漫 我一把揭開白布甜奄。 她就那樣靜靜地躺著柠横,像睡著了一般。 火紅的嫁衣襯著肌膚如雪课兄。 梳的紋絲不亂的頭發(fā)上牍氛,一...
    開封第一講書人閱讀 52,441評(píng)論 1 310
  • 那天,我揣著相機(jī)與錄音烟阐,去河邊找鬼搬俊。 笑死,一個(gè)胖子當(dāng)著我的面吹牛蜒茄,可吹牛的內(nèi)容都是我干的唉擂。 我是一名探鬼主播,決...
    沈念sama閱讀 40,992評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼檀葛,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼玩祟!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起屿聋,我...
    開封第一講書人閱讀 39,899評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤空扎,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后润讥,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體转锈,經(jīng)...
    沈念sama閱讀 46,457評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,529評(píng)論 3 341
  • 正文 我和宋清朗相戀三年楚殿,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了撮慨。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,664評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖砌溺,靈堂內(nèi)的尸體忽然破棺而出菇曲,到底是詐尸還是另有隱情,我是刑警寧澤抚吠,帶...
    沈念sama閱讀 36,346評(píng)論 5 350
  • 正文 年R本政府宣布常潮,位于F島的核電站,受9級(jí)特大地震影響楷力,放射性物質(zhì)發(fā)生泄漏喊式。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,025評(píng)論 3 334
  • 文/蒙蒙 一萧朝、第九天 我趴在偏房一處隱蔽的房頂上張望岔留。 院中可真熱鬧,春花似錦检柬、人聲如沸献联。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,511評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)里逆。三九已至,卻和暖如春用爪,著一層夾襖步出監(jiān)牢的瞬間原押,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,611評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工偎血, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留诸衔,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,081評(píng)論 3 377
  • 正文 我出身青樓颇玷,卻偏偏與公主長(zhǎng)得像笨农,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子帖渠,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,675評(píng)論 2 359

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