<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    生產(chǎn)者與消費者(多線程經(jīng)典案例)

    注:此示例來自MLDN講師李興華JAVA SE基礎(chǔ)教學(xué)部分

    生產(chǎn)者和消費者是多線程中一個經(jīng)典的操作案例下面一起看下代碼:

    示例一:

    package org.lx.multithreading;

    /**
     * 定義一個信息類
     * 
    @author Solitary
     
    */
    class Info {    
        
    private String name = "羅星" ;            //定義name屬性        
        private String content ="JAVA初學(xué)者";    //定義content屬性
        
        
    //getter     setter
        public String getName() {
            
    return name;
        }
        
    public void setName(String name) {
            
    this.name = name;
        }
        
    public String getContent() {
            
    return content;
        }
        
    public void setContent(String content) {
            
    this.content = content;
        }
    } ;

    /**
     * 定義生產(chǎn)者
     * 
    @author Solitary
     
    */
    class Producer implements Runnable {    //通過接口Runnable實現(xiàn)多線程
        private Info info = null ;            //保存Info引用
        
        
    public Producer(Info info) {        //通過構(gòu)造方法傳遞引用
            this.info = info ;
        }
        
        @Override
        
    public void run() {
            
    boolean flag = false ;                //定義標(biāo)志位            
            for(int i = 0; i < 50; i++) {        //生產(chǎn)50次信息
                if(flag){    //如果標(biāo)志位為true 將設(shè)置 中文內(nèi)容
                    this.info.setName("小星") ;    //設(shè)置名字
                    try {
                        
    //為了更好的體現(xiàn)代碼運行效果在設(shè)置姓名和內(nèi)容之間加入延遲操作
                        Thread.sleep(300) ;
                    } 
    catch (InterruptedException e) {        //線程被打斷后會拋出此異常
                        e.printStackTrace();
                    }            
                    
    this.info.setContent("JAVA初學(xué)者") ;        //設(shè)置內(nèi)容
                    flag = false ;    //改變標(biāo)志位,用于變換輸入內(nèi)容
                    
                }
    else{    //如果標(biāo)志位為false 將設(shè)置英文內(nèi)容        
                    this.info.setName("Solitary") ;    //設(shè)置名字
                    try {
                        
    //為了更好的體現(xiàn)代碼運行效果在設(shè)置姓名和內(nèi)容之間加入延遲操作
                        Thread.sleep(300) ;
                    } 
    catch (InterruptedException e) {        //線程被打斷后會拋出此異常
                        e.printStackTrace();
                    }            
                    
    this.info.setContent("Coder") ;        //設(shè)置內(nèi)容
                    flag = true ;    //改變標(biāo)志位,用于變換輸入內(nèi)容
                }
            }
        }    
        
    } ;

    /**
     * 定義消費者
     * 
    @author Solitary
     
    */
    class Consumer implements Runnable {
        
    private Info info = null ;        //用于保存Info引用,其目的是為了讓消費者和生產(chǎn)者擁有同一個info
        
        
    public Consumer(Info info){
            
    this.info = info ;
        }
        
    public void run() {
            
    for(int i = 0; i < 50; i++) {        //消費和也從info中取50次消息
                try {
                    Thread.sleep(
    300) ;
                } 
    catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(
    this.info.getName() + 
                        
    " --> " + this.info.getContent()) ;
            }
        }
    } ;

    /**
     * 測試代碼
     * 
    @author Solitary\
     
    */
    public class MultiThreadingDemo01 {
        
    public static void main(String args[]){        
            Info info 
    = new Info() ;    // 實例化Info對象
            Producer pro = new Producer(info) ;        // 生產(chǎn)者
            Consumer con = new Consumer(info) ;        // 消費者
            new Thread(pro).start() ;        //啟動線程
            new Thread(con).start() ;        //啟動線程        
        }
    }
    示例一(執(zhí)行效果):
    小星 --> Coder
    小星 
    --> JAVA初學(xué)者
    Solitary 
    --> Coder
    小星 
    --> JAVA初學(xué)者
    Solitary 
    --> Coder
    小星 
    --> JAVA初學(xué)者
    Solitary 
    --> Coder
    Solitary 
    --> JAVA初學(xué)者
    Solitary 
    --> Coder
    小星 
    --> JAVA初學(xué)者
    Solitary 
    --> Coder
    小星 
    --> JAVA初學(xué)者
    Solitary 
    --> Coder
    小星 
    --> JAVA初學(xué)者
    Solitary 
    --> JAVA初學(xué)者
    小星 
    --> JAVA初學(xué)者
    Solitary 
    --> Coder
    Solitary 
    --> JAVA初學(xué)者
    Solitary 
    --> Coder
    小星 
    --> Coder
    Solitary 
    --> Coder
    小星 
    --> JAVA初學(xué)者
    Solitary 
    --> Coder
    小星 
    --> JAVA初學(xué)者
    Solitary 
    --> Coder
    小星 
    --> JAVA初學(xué)者
    Solitary 
    --> Coder
    小星 
    --> JAVA初學(xué)者
    Solitary 
    --> Coder
    Solitary 
    --> JAVA初學(xué)者
    小星 
    --> Coder
    小星 
    --> JAVA初學(xué)者
    Solitary 
    --> Coder
    Solitary 
    --> JAVA初學(xué)者
    Solitary 
    --> JAVA初學(xué)者
    小星 
    --> JAVA初學(xué)者
    Solitary 
    --> Coder
    小星 
    --> JAVA初學(xué)者
    Solitary 
    --> JAVA初學(xué)者
    小星 
    --> JAVA初學(xué)者
    小星 
    --> Coder
    小星 
    --> JAVA初學(xué)者
    Solitary 
    --> JAVA初學(xué)者
    小星 
    --> JAVA初學(xué)者
    Solitary 
    --> Coder
    小星 
    --> JAVA初學(xué)者
    Solitary 
    --> Coder
    小星 
    --> JAVA初學(xué)者
    Solitary 
    --> JAVA初學(xué)者
    小星 
    --> JAVA初學(xué)者
    請注意運行結(jié)果,為什么我代碼里面明明成對設(shè)置的是:小星 --> JAVA初學(xué)者;  Solitary --> Coder而運行結(jié)果確實有不匹配的呢?
    分析:
    因為生產(chǎn)者和消費者的線程都已啟動,那么不能保證誰在前,或者誰在后,在生產(chǎn)者還在設(shè)置內(nèi)容的時候(比如:已經(jīng)設(shè)置好的Info的name=小星,Context=JAVA初學(xué)者,而此時生產(chǎn)者又設(shè)置了name = Solitary正打算設(shè)置Content = Coder),而消費者已經(jīng)取走了內(nèi)容,那么顯示的肯定就是Solitary --> JAVA初學(xué)者這樣的結(jié)果,因為兩個線程都在這執(zhí)行著,出現(xiàn)了不匹配的結(jié)果。可以將代碼修改為:

    示例二

    package org.lx.multithreading;

    /**
     * 定義一個信息類
     * 
    @author Solitary
     
    */
    class Info {    
        
    private String name = "羅星" ;            //定義name屬性        
        private String content ="JAVA初學(xué)者";    //定義content屬性
        
        
    //getter     setter
        public String getName() {
            
    return name;
        }
        
    public void setName(String name) {
            
    this.name = name;
        }
        
    public String getContent() {
            
    return content;
        }
        
    public void setContent(String content) {
            
    this.content = content ;
        }
        
        
    public synchronized void set(String name, String content){        //由此方法統(tǒng)一設(shè)置信息
            this.setName(name) ;
            
    try {
                
    /* 此時這個地方加不加延遲沒有任何關(guān)系,因為該方法已經(jīng)同步
                   在執(zhí)行到此方法(get())時,此方法將會完整結(jié)束后才會執(zhí)行
                   到別的方法 ,所以一定會完整設(shè)置完信息之后才會輪到信息的讀取方法
    */
                Thread.sleep(
    300) ;            
            } 
    catch (InterruptedException e) {
                e.printStackTrace();
            }
            
    this.setContent(content) ;
        }
        
        
    public synchronized void get(){
            
    try {
                Thread.sleep(
    300) ;
            } 
    catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(
    this.getName() + 
                    
    " --> " + this.getContent()) ;
        }
    } ;

    /**
     * 定義生產(chǎn)者
     * 
    @author Solitary
     
    */
    class Producer implements Runnable {    //通過接口Runnable實現(xiàn)多線程
        private Info info = null ;            //保存Info引用
        
        
    public Producer(Info info) {        //通過構(gòu)造方法傳遞引用
            this.info = info ;
        }
        
        @Override
        
    public void run() {
            
    boolean flag = false ;                //定義標(biāo)志位            
            for(int i = 0; i < 50; i++) {        //生產(chǎn)50次信息
                if(flag){    //如果標(biāo)志位為true 將設(shè)置 中文內(nèi)容
                    this.info.set("小星""JAVA初學(xué)者") ;
                    flag 
    = false ;    //改變標(biāo)志位,用于變換輸入內(nèi)容
                    
                }
    else{    //如果標(biāo)志位為false 將設(shè)置英文內(nèi)容        
                    this.info.set("Solitary""Coder") ;
                    flag 
    = true ;    //改變標(biāo)志位,用于變換輸入內(nèi)容
                }
            }
        }    
        
    } ;

    /**
     * 定義消費者
     * 
    @author Solitary
     
    */
    class Consumer implements Runnable {
        
    private Info info = null ;        //用于保存Info引用,其目的是為了讓消費者和生產(chǎn)者擁有同一個info
        
        
    public Consumer(Info info){
            
    this.info = info ;
        }
        
    public void run() {
            
    for(int i = 0; i < 50; i++) {        //消費和也從info中取50次消息
                this.info.get() ;
            }
        }
    } ;

    /**
     * 測試代碼
     * 
    @author Solitary\
     
    */
    public class MultiThreadingDemo01 {
        
    public static void main(String args[]){        
            Info info 
    = new Info() ;    // 實例化Info對象
            Producer pro = new Producer(info) ;        // 生產(chǎn)者
            Consumer con = new Consumer(info) ;        // 消費者
            new Thread(pro).start() ;        //啟動線程
            new Thread(con).start() ;        //啟動線程        
        }
    }
    示例二(運行效果)
    Solitary --> Coder
    Solitary 
    --> Coder
    Solitary 
    --> Coder
    Solitary 
    --> Coder
    Solitary 
    --> Coder
    Solitary 
    --> Coder
    小星 
    --> JAVA初學(xué)者
    Solitary 
    --> Coder
    小星 
    --> JAVA初學(xué)者
    Solitary 
    --> Coder
    小星 
    --> JAVA初學(xué)者
    Solitary 
    --> Coder
    小星 
    --> JAVA初學(xué)者
    小星 
    --> JAVA初學(xué)者
    小星 
    --> JAVA初學(xué)者
    小星 
    --> JAVA初學(xué)者
    小星 
    --> JAVA初學(xué)者
    小星 
    --> JAVA初學(xué)者
    小星 
    --> JAVA初學(xué)者
    小星 
    --> JAVA初學(xué)者
    小星 
    --> JAVA初學(xué)者
    小星 
    --> JAVA初學(xué)者
    小星 
    --> JAVA初學(xué)者
    小星 
    --> JAVA初學(xué)者
    小星 
    --> JAVA初學(xué)者
    小星 
    --> JAVA初學(xué)者
    小星 
    --> JAVA初學(xué)者
    小星 
    --> JAVA初學(xué)者
    小星 
    --> JAVA初學(xué)者
    小星 
    --> JAVA初學(xué)者
    小星 
    --> JAVA初學(xué)者
    小星 
    --> JAVA初學(xué)者
    小星 
    --> JAVA初學(xué)者
    小星 
    --> JAVA初學(xué)者
    小星 
    --> JAVA初學(xué)者
    小星 
    --> JAVA初學(xué)者
    小星 
    --> JAVA初學(xué)者
    小星 
    --> JAVA初學(xué)者
    小星 
    --> JAVA初學(xué)者
    小星 
    --> JAVA初學(xué)者
    小星 
    --> JAVA初學(xué)者
    小星 
    --> JAVA初學(xué)者
    小星 
    --> JAVA初學(xué)者
    小星 
    --> JAVA初學(xué)者
    小星 
    --> JAVA初學(xué)者
    小星 
    --> JAVA初學(xué)者
    小星 
    --> JAVA初學(xué)者
    小星 
    --> JAVA初學(xué)者
    小星 
    --> JAVA初學(xué)者
    觀察運行結(jié)果發(fā)現(xiàn),不匹配的現(xiàn)象已經(jīng)解決了,因為設(shè)置name 與 content 的步驟都在一個同步方法中,所以不會導(dǎo)致設(shè)置不完整的情況,但是并沒有達(dá)到我們想要的結(jié)果, 觀察出現(xiàn)了連續(xù)出現(xiàn)重復(fù)的內(nèi)容,這是為什么呢? 分析:這兩個方法在不同的線程中,當(dāng)一條線程中的方法設(shè)置完內(nèi)容之后,另一個線程取出內(nèi)容顯示,取完之后當(dāng)了土財主不讓,繼續(xù)取,生產(chǎn)者無法更新里邊的內(nèi)容,那顯示出來的內(nèi)容肯定就是重復(fù)的,因為多線程中,不能保證這個線程什么時候執(zhí)行。怎樣解決呢?

    1.中間那塊矩形代表信息載體Info實例,載體中沒有產(chǎn)品的時候上面顯示為綠燈,那么這時生產(chǎn)者能放入產(chǎn)品。而消費者不能取出產(chǎn)品。


    2.當(dāng)生產(chǎn)者放入產(chǎn)品之后燈變成紅色,這時候生產(chǎn)者將不能放入產(chǎn)品,而輪到消費者取出產(chǎn)品,那么去完之后再次改變燈為綠色。這樣一直反復(fù)執(zhí)行下去。

    那么載體上的那盞燈屬于一個標(biāo)志位,我們可以在代碼中用boolean表示,那么這盞燈是屬于信息載體Info的標(biāo)志,因為設(shè)置/取出這兩個方法都在Info中定義,生產(chǎn)者與消費者只是負(fù)責(zé)調(diào)用Info之中的方法,就讓Info中的方法判斷一下自身的標(biāo)志位的狀態(tài)判斷是否生產(chǎn)或者取出。

    實例三
    package org.lx.multithreading ;

    class Info        //定義信息類
    {
        
    private String name = "羅星" ;        //定義name屬性
        private String content = "JAVA初學(xué)者" ;        //定義content屬性
        private boolean flag = false ;    //設(shè)置標(biāo)志位


        
    public synchronized void set(String name, String content){
            
    if(!flag){        //方法每次執(zhí)行的時候都檢查一下標(biāo)志位狀態(tài),從而判斷時候進(jìn)行生產(chǎn)
                try{
                    
    super.wait() ;
                }
    catch(InterruptedException e){
                    e.printStackTrace() ;
                }
            }
            
    this.setName(name) ;        //設(shè)置名稱
            try{
                Thread.sleep(
    300) ;
            }
    catch(InterruptedException e){
                e.printStackTrace() ;
            }
            
    this.setContent(content) ;    // 設(shè)置內(nèi)容
            flag = false ;        //改變標(biāo)志位,表示可以取走
            super.notify() ;    //喚醒線程
        }

        
    public synchronized void get(){
            
    if(flag){        ////方法每次執(zhí)行的時候都檢查一下標(biāo)志位狀態(tài),從而判斷時候進(jìn)行取出
                try{
                    
    super.wait() ;
                }
    catch(InterruptedException e){
                    e.printStackTrace() ;
                }
            }
            
    try{
                Thread.sleep(
    300) ;
            }
    catch(InterruptedException e){
                e.printStackTrace() ;
            }
            System.out.println(
    this.getName() +
                    
    " --> " + this.getContent()) ;
            flag 
    = true ;    //改變標(biāo)志位,表示可以生成    
            super.notify() ;
        }

        
    public void setName(String name){
            
    this.name = name ;
        }

        
    public String getName(){
            
    return this.name ;
        }

        
    public void setContent(String content){
            
    this.content = content ;
        }

        
    public String getContent(){
            
    return this.content ;
        }
    }

    class Producer implements Runnable        //通過Runnable實現(xiàn)多線程
    {
        
    public Info info = null ;        //保存Info引用
        public Producer(Info info){
            
    this.info = info ;
        }

        
    public void run(){
            
    boolean flag = false ;    //定義標(biāo)記位
            for(int i = 0; i < 50; i++){
                
    if(flag){
                    
    this.info.set("羅星""JAVA初學(xué)者") ;
                    flag 
    = false ;
                }
    else{
                    
    this.info.set("Solitary""Coder") ;
                    flag 
    = true ;
                }
            }
        }
    } ;

    class Consumer implements Runnable{        //消費者類
        private Info info = null ;        
        
    public Consumer(Info info){
            
    this.info = info ;
        }

        
    public void run(){
            
    for(int i = 0; i < 50; i++){
                
    this.info.get() ;
            }
        }
    } ;

    //測試代碼
    public class MultiThreading
    {
        
    public static void main(String[] args){
            Info info 
    = new Info() ;    //實例化Info對象
            Producer pro = new Producer(info) ;    //生產(chǎn)者
            Consumer con = new Consumer(info) ;    //消費者
            new Thread(pro).start() ;
            
    new Thread(con).start() ;
        }
    }
    在此利用了Object類對線程的支持,Object中定義了方法:
    public final void wait() throws InterruptedException
    在其他線程調(diào)用此對象的 notify() 方法或 notifyAll() 方法前,導(dǎo)致當(dāng)前線程等待。
    換句話說,此方法的行為就好像它僅執(zhí)行 wait(0) 調(diào)用一樣。

    當(dāng)前線程必須擁有此對象監(jiān)視器。該線程發(fā)布對此監(jiān)視器的所有權(quán)并等待,直到其他線程通過調(diào)用 notify 方法,或 notifyAll 方法通知在此對象的監(jiān)視器上等待的線程醒來。然后該線程將等到重新獲得對監(jiān)視器的所有權(quán)后才能繼續(xù)執(zhí)行。 

    public final void notify()
    喚醒在此對象監(jiān)視器上等待的單個線程。如果所有線程都在此對象上等待,則會選擇喚醒其中一個線程。選擇是任意性的,并在對實現(xiàn)做出決定時發(fā)生。線程通過調(diào)用其中一個 wait 方法,在對象的監(jiān)視器上等待。

    直到當(dāng)前線程放棄此對象上的鎖定,才能繼續(xù)執(zhí)行被喚醒的線程。被喚醒的線程將以常規(guī)方式與在該對象上主動同步的其他所有線程進(jìn)行競爭;例如,喚醒的線程在作為鎖定此對象的下一個線程方面沒有可靠的特權(quán)或劣勢。  

    當(dāng)生產(chǎn)者線程調(diào)用此方法時,首先檢查一下標(biāo)志位,判斷是否等待,此時消費者也在調(diào)用相應(yīng)方法判斷是否取出,如果可以取出,那么取出后改變標(biāo)志位的狀態(tài),然后喚醒該對象中等待的線程,這時狀態(tài)改變生產(chǎn)者既進(jìn)行生產(chǎn)操作。


    序言:
    小弟是一個JAVA新手,這也是第一次寫博客,此文純屬于學(xué)習(xí)筆記,以便日后復(fù)習(xí),如果前輩們認(rèn)為描述有錯誤的地方,或者覺得不清晰感覺思路混亂的地方,還請前輩們多多賜教,晚生感激不勝! 謝謝。

    posted on 2011-10-29 18:26 Solitary 閱讀(2309) 評論(1)  編輯  收藏

    評論

    # re: 生產(chǎn)者與消費者(多線程經(jīng)典案例) 2014-11-11 21:53 李興華

    親,你這明顯是抄襲我的嘛,我是魔樂科技的李興華;
    希望你能改過自新  回復(fù)  更多評論   


    只有注冊用戶登錄后才能發(fā)表評論。


    網(wǎng)站導(dǎo)航:
     
    <2014年11月>
    2627282930311
    2345678
    9101112131415
    16171819202122
    23242526272829
    30123456

    導(dǎo)航

    統(tǒng)計

    常用鏈接

    留言簿(1)

    隨筆分類

    隨筆檔案

    搜索

    最新評論

    閱讀排行榜

    評論排行榜

    主站蜘蛛池模板: 亚洲一区影音先锋色资源| 亚洲国产精品嫩草影院在线观看 | JLZZJLZZ亚洲乱熟无码| 亚洲精品伦理熟女国产一区二区| 精品国产免费人成电影在线观看| 久久亚洲精品无码VA大香大香| 久操免费在线观看| 91亚洲国产成人精品下载| 成人免费视频网站www| 精品日韩99亚洲的在线发布| 在线观看H网址免费入口| 亚洲狠狠成人综合网| 最近中文字幕无免费视频| 亚洲av乱码一区二区三区按摩| 青青青青青青久久久免费观看| 相泽南亚洲一区二区在线播放| 免费一级e一片在线播放| 毛片基地看看成人免费| 亚洲国产天堂在线观看| 国产免费不卡v片在线观看| 亚洲youwu永久无码精品| 亚洲AV中文无码乱人伦在线视色| av片在线观看永久免费| 亚洲AV日韩精品久久久久| 2020久久精品国产免费| 亚洲AV无码之国产精品| 国产精品亚洲二区在线观看| 国产精成人品日日拍夜夜免费| 亚洲视频一区二区三区四区| 亚洲阿v天堂在线2017免费| 麻豆精品成人免费国产片| 亚洲成a人片在线看| 亚洲 小说区 图片区 都市| 野花香高清视频在线观看免费| 亚洲国色天香视频| 亚洲va中文字幕无码| 99久久久国产精品免费蜜臀| 亚洲中文无码mv| 亚洲乱码中文字幕久久孕妇黑人| 最近中文字幕大全中文字幕免费| 亚洲综合无码无在线观看|