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

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

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

    Java學(xué)習(xí)

    java,spring,structs,hibernate,jsf,ireport,jfreechart,jasperreport,tomcat,jboss -----本博客已經(jīng)搬家了,新的地址是 http://www.javaly.cn 如果有對(duì)文章有任何疑問或者有任何不懂的地方,歡迎到www.javaly.cn (Java樂園)指出,我會(huì)盡力幫助解決。一起進(jìn)步

     

    多線程問題及處理2

    如果這個(gè)例子還不能幫助你理解如何解決多線程的問題,那么下面再來看一個(gè)更加實(shí)際的例子——衛(wèi)生間問題。

             例 如火車上車廂的衛(wèi)生間,為了簡單,這里只模擬一個(gè)衛(wèi)生間,這個(gè)衛(wèi)生間會(huì)被多個(gè)人同時(shí)使用,在實(shí)際使用時(shí),當(dāng)一個(gè)人進(jìn)入衛(wèi)生間時(shí)則會(huì)把衛(wèi)生間鎖上,等出來時(shí) 打開門,下一個(gè)人進(jìn)去把門鎖上,如果有一個(gè)人在衛(wèi)生間內(nèi)部則別人的人發(fā)現(xiàn)門是鎖的則只能在外面等待。從編程的角度來看,這里的每個(gè)人都可以看作是一個(gè)線程 對(duì)象,而這個(gè)衛(wèi)生間對(duì)象由于被多個(gè)線程訪問,則就是臨界資源,在一個(gè)線程實(shí)際使用時(shí),使用synchronized關(guān)鍵將臨界資源鎖定,當(dāng)結(jié)束時(shí),釋放鎖定。實(shí)現(xiàn)的代碼如下:

                      package syn3;

    /**

     * 測試類

     */

    public class TestHuman {

             public static void main(String[] args) {

                       Toilet t = new Toilet(); //衛(wèi)生間對(duì)象

                       Human h1 = new Human("1",t);

                       Human h2 = new Human("2",t);

                       Human h3 = new Human("3",t);

             }

    }

    package syn3;

    /**

     * 人線程類,演示互斥

     */

    public class Human extends Thread {

             Toilet t;

             String name;

             public Human(String name,Toilet t){

                       this.name = name;

                       this.t = t;

                       start(); //啟動(dòng)線程

             }

            

             public void run(){

                       //進(jìn)入衛(wèi)生間

                       t.enter(name);

             }

    }

    package syn3;

    /**

     * 衛(wèi)生間,互斥的演示

     */

    public class Toilet {

             public synchronized void enter(String name){

                       System.out.println(name + "已進(jìn)入!");

                       try{

                                Thread.sleep(2000);

                       }catch(Exception e){}

                       System.out.println(name + "離開!");

             }

    }

             該示例的執(zhí)行結(jié)果為,不同次數(shù)下執(zhí)行結(jié)果會(huì)有所不同:

                       1已進(jìn)入!

    1離開!

    3已進(jìn)入!

    3離開!

    2已進(jìn)入!

    2離開!

             在該示例代碼中,Toilet類表示衛(wèi)生間類,Human類模擬人,是該示例中的線程類,TestHuman類是測試類,用于啟動(dòng)線程。在TestHuman中,首先創(chuàng)建一個(gè)Toilet類型的對(duì)象t,并將該對(duì)象傳遞到后續(xù)創(chuàng)建的線程對(duì)象中,這樣后續(xù)的線程對(duì)象就使用同一個(gè)Toilet對(duì)象,該對(duì)象就成為了臨界資源。下面創(chuàng)建了三個(gè)Human類型的線程對(duì)象,每個(gè)線程具有自己的名稱name參數(shù),模擬3個(gè)線程,在每個(gè)線程對(duì)象中,只是調(diào)用對(duì)象t中的enter方法,模擬進(jìn)入衛(wèi)生間的動(dòng)作,在enter方法中,在進(jìn)入時(shí)輸出調(diào)用該方法的線程進(jìn)入,然后延遲2秒,輸出該線程離開,然后后續(xù)的一個(gè)線程進(jìn)入,直到三個(gè)線程都完成enter方法則程序結(jié)束。

             在該示例中,同一個(gè)Toilet類的對(duì)象tenter方法由于具有synchronized修飾符修飾,則在多個(gè)線程同時(shí)調(diào)用該方法時(shí),如果一個(gè)線程進(jìn)入到enter方法內(nèi)部,則為對(duì)象t上鎖,直到enter方法結(jié)束以后釋放對(duì)該對(duì)象的鎖定,通過這種方式實(shí)現(xiàn)無論多少個(gè)Human類型的線程,對(duì)于同一個(gè)對(duì)象t,任何時(shí)候只能有一個(gè)線程執(zhí)行enter方法,這就是解決多線程問題的第一種思路——互斥的解決原理。

    12.4.2 同步

             使用互斥解決多線程問題是一種簡單有效的解決辦法,但是由于該方法比較簡單,所以只能解決一些基本的問題,對(duì)于復(fù)雜的問題就無法解決了。

             解 決多線程問題的另外一種思路是同步。同步是另外一種解決問題的思路,結(jié)合前面衛(wèi)生間的示例,互斥方式解決多線程的原理是,當(dāng)一個(gè)人進(jìn)入到衛(wèi)生間內(nèi)部時(shí),別 的人只能在外部時(shí)刻等待,這樣就相當(dāng)于別的人雖然沒有事情做,但是還是要占用別的人的時(shí)間,浪費(fèi)系統(tǒng)的執(zhí)行資源。而同步解決問題的原理是,如果一個(gè)人進(jìn)入 到衛(wèi)生間內(nèi)部時(shí),則別的人可以去睡覺,不占用系統(tǒng)資源,而當(dāng)這個(gè)人從衛(wèi)生間出來以后,把這個(gè)睡覺的人叫醒,則它就可以使用臨界資源了。所以使用同步的思路 解決多線程問題更加有效,更加節(jié)約系統(tǒng)的資源。

             在常見的多線程問題解決中,同步問題的典型示例是“生產(chǎn)者-消費(fèi)者”模型,也就是生產(chǎn)者線程只負(fù)責(zé)生產(chǎn),消費(fèi)者線程只負(fù)責(zé)消費(fèi),在消費(fèi)者發(fā)現(xiàn)無內(nèi)容可消費(fèi)時(shí)則睡覺。下面舉一個(gè)比較實(shí)際的例子——生活費(fèi)問題。

             生 活費(fèi)問題是這樣的:學(xué)生每月都需要生活費(fèi),家長一次預(yù)存一段時(shí)間的生活費(fèi),家長和學(xué)生使用統(tǒng)一的一個(gè)帳號(hào),在學(xué)生每次取帳號(hào)中一部分錢,直到帳號(hào)中沒錢時(shí) 通知家長存錢,而家長看到帳戶還有錢則不存錢,直到帳戶沒錢時(shí)才存錢。在這個(gè)例子中,這個(gè)帳號(hào)被學(xué)生和家長兩個(gè)線程同時(shí)訪問,則帳號(hào)就是臨界資源,兩個(gè)線 程是同時(shí)執(zhí)行的,當(dāng)每個(gè)線程發(fā)現(xiàn)不符合要求時(shí)則等待,并釋放分配給自己的CPU執(zhí)行時(shí)間,也就是不占用系統(tǒng)資源。實(shí)現(xiàn)該示例的代碼為:

                       package syn4;

    /**

     * 測試類

     */

    public class TestAccount {

             public static void main(String[] args) {

                       Accout a = new Accout();

                       StudentThread s = new StudentThread(a);

                       GenearchThread g = new GenearchThread(a);

             }

    }

    package syn4;

    /**

     * 模擬學(xué)生線程

     */

    public class StudentThread extends Thread {

             Accout a;

             public StudentThread(Accout a){

                       this.a = a;

                       start();

             }

             public void run(){

                       try{

                                while(true){

                                         Thread.sleep(2000);

                                         a.getMoney(); //取錢

                                }

                       }catch(Exception e){}

             }

    }

    package syn4;

    /**

     * 家長線程

     */

    public class GenearchThread extends Thread {

             Accout a;

             public GenearchThread(Accout a){

                       this.a = a;

                       start();

             }

             public void run(){

                       try{

                                while(true){

                                         Thread.sleep(12000);

                                         a.saveMoney(); //存錢

                                }

                       }catch(Exception e){}

             }

    }

    package syn4;

    /**

     * 銀行賬戶

     */

    public class Accout {

             int money = 0;

             /**

              * 取錢

              * 如果賬戶沒錢則等待,否則取出所有錢提醒存錢

              */

             public synchronized void getMoney(){

                       System.out.println("準(zhǔn)備取錢!");

                       try{

                                if(money == 0){

                                         wait(); //等待

                                }

                                //取所有錢

                                System.out.println("剩余:" + money);

                                money -= 50;

                                //提醒存錢

                                notify();

                       }catch(Exception e){}                

             }

            

             /**

              * 存錢

              * 如果有錢則等待,否則存入200提醒取錢

              */

             public synchronized void saveMoney(){

                       System.out.println("準(zhǔn)備存錢!");

                       try{

                                if(money != 0){

                                         wait(); //等待

                                }

                                //取所有錢

                                money = 200;

                                System.out.println("存入:" + money);

                                //提醒存錢

                                notify();

                       }catch(Exception e){}                

             }

    }

             該程序的一部分執(zhí)行結(jié)果為:

                       準(zhǔn)備取錢!

    準(zhǔn)備存錢!

    存入:200

    剩余:200

    準(zhǔn)備取錢!

    剩余:150

    準(zhǔn)備取錢!

    剩余:100

    準(zhǔn)備取錢!

    剩余:50

    準(zhǔn)備取錢!

    準(zhǔn)備存錢!

    存入:200

    剩余:200

    準(zhǔn)備取錢!

    剩余:150

    準(zhǔn)備取錢!

    剩余:100

    準(zhǔn)備取錢!

    剩余:50

    準(zhǔn)備取錢!

             在該示例代碼中,TestAccount類是測試類,主要實(shí)現(xiàn)創(chuàng)建帳戶Account類的對(duì)象,以及啟動(dòng)學(xué)生線程StudentThread和啟動(dòng)家長線程GenearchThread。在StudentThread線程中,執(zhí)行的功能是每隔2秒中取一次錢,每次取50元。在GenearchThread線程中,執(zhí)行的功能是每隔12秒存一次錢,每次存200。這樣存款和取款之間不僅時(shí)間間隔存在差異,而且數(shù)量上也會(huì)出現(xiàn)交叉。而該示例中,最核心的代碼是Account類的實(shí)現(xiàn)。

             Account類中,實(shí)現(xiàn)了同步控制功能,在該類中包含一個(gè)關(guān)鍵的屬性money,該屬性的作用是存儲(chǔ)帳戶金額。在介紹該類的實(shí)現(xiàn)前,首先介紹一下兩個(gè)同步方法——waitnotify方法的使用,這兩個(gè)方法都是Object類中的方法,也就是說每個(gè)類都包含這兩個(gè)方法,換句話說,就是Java天生就支持同步處理。這兩個(gè)方法都只能在synchronized修飾的方法或語句塊內(nèi)部采用被調(diào)用。其中wait方法的作用是使調(diào)用該方法的線程休眠,也就是使該線程退出CPU的等待隊(duì)列,處于冬眠狀態(tài),不執(zhí)行動(dòng)作,也不占用CPU排隊(duì)的時(shí)間,notify方法的作用是喚醒一個(gè)因?yàn)樵搶?duì)象的線程,該線程當(dāng)前處于休眠狀態(tài),至于喚醒的具體是那個(gè)則不保證。在Account類中,被StudentThread調(diào)用的getMoney方法的功能是判斷當(dāng)前金額是否是0,如果是則使StudentThread線程處于休眠狀態(tài),如果金額不是0,則取出50元,同時(shí)喚醒使用該帳戶對(duì)象的其它一個(gè)線程,而被GenearchThread線程調(diào)用的saveMoney方法的功能是判斷當(dāng)前是否不為0,如果是則使GenearchThread線程處于休眠狀態(tài),如果金額是0,則存入200元,同時(shí)喚醒使用該帳戶對(duì)象的其它一個(gè)線程。

             如果還是不清楚,那就結(jié)合前面的程序執(zhí)行結(jié)果來解釋一下程序執(zhí)行的過程:在程序開始執(zhí)行時(shí),學(xué)生線程和家長線程都啟動(dòng)起來,所以輸出“準(zhǔn)備取錢”和“準(zhǔn)備存錢”,然后學(xué)生線程按照該線程run方法的邏輯執(zhí)行,先延遲2秒,然后調(diào)用帳戶對(duì)象a中的getMoney方法,但是由于初始情況下帳戶對(duì)象a中的money數(shù)值為0,所以學(xué)生線程就休眠了。在學(xué)生線程執(zhí)行的同時(shí),家長線程也按照該線程的run方法的邏輯執(zhí)行,先延遲12秒,然后調(diào)用帳戶對(duì)象a中的saveMoney方法,由于帳戶a對(duì)象中的money為零,條件不成立,所以執(zhí)行存入200元,同時(shí)喚醒線程,由于使用對(duì)象a的線程現(xiàn)在只有學(xué)生線程,所以學(xué)生線程被喚醒,開始執(zhí)行邏輯,取出50元,然后喚醒線程,由于當(dāng)前沒有線程處于休眠狀態(tài),所以沒有線程被喚醒。同時(shí)家長線程繼續(xù)執(zhí)行,先延遲12秒,這個(gè)時(shí)候?qū)W生線程執(zhí)行了4次,耗時(shí)4X2=8秒,就取光了帳戶中的錢,接著由于帳戶為0則學(xué)生線程又休眠了,一直到家長線程延遲12秒結(jié)束以后,判斷帳戶為0,又存入了200元,程序繼續(xù)執(zhí)行下去。

             在解決多線程問題是,互斥和同步都是解決問題的思路,如果需要形象的比較這兩種方式的區(qū)別的話,就看一下下面的示例。一個(gè)比較忙的老總,桌子上有2部電話,在一部處于通話狀態(tài)時(shí),另一部響了,老總拿其這部電話說我在接電話,你等一下,而沒有掛電話,這種處理的方式就是互斥。而如果老總拿其另一部電話說,我在接電話,等會(huì)我打給你,然后掛了電話,這種處理的方式就是同步。兩者相比,互斥明顯占用系統(tǒng)資源(浪費(fèi)電話費(fèi),浪費(fèi)別人的時(shí)間),而同步則是一種更加好的解決問題的思路。


    zhuan:http://blog.csdn.net/Mailbomb/archive/2009/05/27/4220846.aspx

    posted on 2009-06-15 13:25 找個(gè)美女做老婆 閱讀(247) 評(píng)論(0)  編輯  收藏


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


    網(wǎng)站導(dǎo)航:
     

    導(dǎo)航

    統(tǒng)計(jì)

    公告

    本blog已經(jīng)搬到新家了, 新家:www.javaly.cn
     http://www.javaly.cn

    常用鏈接

    留言簿(6)

    隨筆檔案

    文章檔案

    搜索

    最新評(píng)論

    閱讀排行榜

    評(píng)論排行榜

    主站蜘蛛池模板: 亚洲人成在线播放网站岛国| 亚洲AV无码久久精品狠狠爱浪潮| 国语成本人片免费av无码 | 9i9精品国产免费久久| 中文在线免费观看| 亚洲人成色7777在线观看不卡| 亚洲好看的理论片电影| 久久香蕉国产线看免费| 日本免费一区二区三区最新vr| 亚洲最大黄色网址| 国产精品视频免费| 亚洲人成网亚洲欧洲无码| a级片免费在线观看| 亚洲色婷婷综合久久| 亚洲男同gay片| 国产极品美女高潮抽搐免费网站| 亚洲AV日韩综合一区| 免费大黄网站在线观看| 一个人免费播放在线视频看片| 亚洲欧洲精品成人久久曰影片| 男女一进一出抽搐免费视频| 亚洲精品无码MV在线观看| 亚洲国产精品ⅴa在线观看| 国产资源免费观看| 亚洲免费在线观看| 亚洲AV日韩AV永久无码下载| 一级毛片免费在线播放| 国产亚洲综合网曝门系列| 1000部羞羞禁止免费观看视频| 亚洲日韩欧洲乱码AV夜夜摸 | 欧美色欧美亚洲另类二区| 亚洲AV无码乱码在线观看性色扶| 韩国免费A级毛片久久| 亚洲综合激情六月婷婷在线观看| 一区二区无码免费视频网站 | 成全视频在线观看免费高清动漫视频下载 | 日本高清免费中文字幕不卡| 久久最新免费视频| 亚洲精品无码久久毛片波多野吉衣| 最近中文字幕mv免费高清电影| 男人和女人高潮免费网站|