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

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

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

    我的漫漫程序之旅

    專注于JavaWeb開發
    隨筆 - 39, 文章 - 310, 評論 - 411, 引用 - 0
    數據加載中……

    多線程編程的設計模式 臨界區模式

    臨界區模式 Critical Section Pattern 是指在一個共享范圍中只讓一個線程執行的模式.
    它是所有其它多線程設計模式的基礎,所以我首先來介紹它.
    把著眼點放在范圍上,這個模式叫臨界區模式,如果把作眼點放在執行的線程上,這個模式就叫
    單線程執行模式.

    首先我們來玩一個鉆山洞的游戲,我 Axman,朋友 Sager,同事 Pentium4.三個人在八角游樂場
    循環鉆山洞(KAO,減肥訓練啊),每個人手里有一個牌子,每鉆一次洞口的老頭會把當前的次序,
    姓名,牌號顯示出來,并檢查名字與牌號是否一致.

    OK,這個游戲的參與者有游樂場老頭Geezer,Player,就是我們,還有山洞 corrie.

    public class Geezer {
    public static void main(String[] args){

    System.out.println(
    "預備,開始!"); 
    Corrie c 
    = new Corrie(); //只有一個山洞,所以生存一個實例后傳給多個Player.
    new Player("Axman","001",c).start(); 
    new Player("Sager","002",c).start(); 
    new Player("Pentium4","003",c).start(); 
    }

    }


    這個類暫時沒有什么多說的,它是一個Main的角色.
    public class Player extends Thread{
    private final String name; 
    private final String number; 
    private final Corrie corrie; 
    public Player(String name,String number,Corrie corrie) {
    this.name = name; 
    this.number = number; 
    this.corrie = corrie; 
    }


    public void run(){
    while(true){
    this.corrie.into(this.name,this.number); 
    }

    }

    }


    在這里,我們把成員字段都設成final的,為了說明一個Player一旦構造,他的名字和牌號就不能改
    變,簡單說在游戲中,我,Sager,Pentium4三個人不會自己偷偷把自己的牌號換了,也不會偷偷地去
    鉆別的山洞,如果這個游戲一旦發生錯誤,那么錯誤不在我們玩家.

    import java.util.*
    public class Corrie {
    private int count = 0
    private String name; 
    private String number; 
    private HashMap lib = new HashMap(); //保存姓名與牌號的庫

    public Corrie(){

    lib.put(
    "Axman","001"); 
    lib.put(
    "Sager","002"); 
    lib.put(
    "Pentium4","003"); 

    }


    public void into(String name,String number){
    this.count ++
    this.name = name; 
    this.number = number; 
    if(this.lib.get(name).equals(number))
    test():
    }


    public String display(){
    return this.count+"" + this.name + "(" + this.number + ")"
    }


    private void test(){
    if(this.lib.get(name).equals(number))

    //System.out.println("OK:" + display()); 
    else
    System.out.println(
    "ERR:" + display()); 
    }

    }



    這個類中增加了一個lib的HashMap,相當于一個玩家姓名與牌號的庫,因為明知道Corrie只有一個實例,
    所以我用了成員對象而不是靜態實例,只是為了能在構造方法中初始化庫中的內容,從真正意義中說應
    該在一個輔助類中實現這樣的數據結構封裝的功能.如果不提供這個lib,那么在check的時候就要用
    if(name.equasl("Axman")){
    if(!number.equals("001")) //出錯
    }

    else if .

    這樣復雜的語句,如果player大多可能會寫到手抽筋,所以用一個lib來chcek就非常容象.


    運行這個程序需要有一些耐心,因為即使你的程序寫得再差在很多單線程測試環境下也能可是正確的.
    而且多線程程序在不同的機器上表現不同,要發現這個例子的錯識,可能要運行很長一段時間,如果你的
    機器是多CPU的,那么出現錯誤的機會就大好多.

    在我的筆記本上最終出現錯誤是在11分鐘以后,出現的錯誤有幾鐘情況:
    1: ERR:Axman(003)
    2: ERR:Sager(002)


    第一種情況是檢查到了錯誤,我的牌號明明是001,卻打印出來003,而第二種明明沒有錯誤,卻打印了錯誤.

    事實上根據以前介紹的多線程知識,不難理解這個例子的錯誤出現,因為into不是線程安全的,所以在其中
    一個線程執行this.name = "Axman"; 后,本來應該執行this.numner="001",卻被切換到另一個線程中執行
    this.number="003",然后又經過不可預知的切換執行其中一個的if(this.lib.get(name).equals(number))
    而出現1的錯誤,而在打印這個錯誤時因為display也不是線程安全的,正要打印一個錯誤的結果時,由于
    this.name或this.number其中一個字段被修改卻成了正確的匹配而出現錯誤2.

    另外還有可能會出現序號顛倒或不對應,但這個錯誤我們無法直觀地觀察,因為你根本不知道哪個序號"應該"
    給哪個Player,而序號顛倒則有可能被滾動的屏幕所掩蓋.


    [正確的Critical Section模式的例子]
    我們知道出現這些錯誤是因為Corrie類的方法不是線程安全的,那么只要修改Corrie類為線程安全的類就行
    了.其它類則不需要修改,上面說過,如果出現錯誤那一定不是我們玩家的事:

    import java.util.*
    public class Corrie {
    private int count = 0
    private String name; 
    private String number; 
    private HashMap lib = new HashMap(); //保存姓名與牌號的庫

    public Corrie(){

    lib.put(
    "Axman","001"); 
    lib.put(
    "Sager","002"); 
    lib.put(
    "Pentium4","003"); 

    }


    public synchronized void into(String name,String number){
    this.count ++
    this.name = name; 
    this.number = number; 
    test(); 
    }


    public synchronized String display(){
    return this.count+"" + this.name + "(" + this.number + ")"
    }


    private void test(){
    if(this.lib.get(name).equals(number))

    //System.out.println("OK:" + display()); 
    else
    System.out.println(
    "ERR:" + display()); 
    }

    }




    運行這個例子,如果你的耐心,開著你的機器運行三天吧.雖然測試100天并不能說明第101天沒有出錯,
    at least,現在的正確性比原來那個沒有synchronized 保護的例子要可靠多了!

    到這里我們對Critical Section模式的例程有了直觀的了解,在詳細解說這個模式之前,請想一下,test
    方法安全嗎?為什么?


    posted on 2008-01-06 22:20 々上善若水々 閱讀(492) 評論(0)  編輯  收藏 所屬分類: J2SE

    主站蜘蛛池模板: 免费一本色道久久一区| 麻豆亚洲AV永久无码精品久久| 免费一级毛片清高播放| 国产日韩在线视频免费播放| 99久久婷婷国产综合亚洲| 久久亚洲国产精品一区二区| 免费a级黄色毛片| 男男AV纯肉无码免费播放无码| 2019亚洲午夜无码天堂| 亚洲av无码不卡| 国产成人精品久久亚洲| 国产精品美女自在线观看免费| 亚洲youwu永久无码精品| 亚洲精品美女久久久久| 国产亚洲综合久久系列| 亚洲成?Ⅴ人在线观看无码| 搡女人免费视频大全| 1000部禁片黄的免费看| 成人网站免费大全日韩国产| 另类图片亚洲校园小说区| 亚洲日韩一区精品射精| 亚洲黄色在线网站| 亚洲成人中文字幕| 亚洲av鲁丝一区二区三区| 亚洲狠狠婷婷综合久久久久| 国产自偷亚洲精品页65页| 亚洲精品尤物yw在线影院| 免费一级毛片在播放视频| 四虎影视精品永久免费网站| 午夜视频在线观看免费完整版| 一级特黄录像免费播放肥| 国产区图片区小说区亚洲区| 亚洲最大中文字幕无码网站| 亚洲五月丁香综合视频| 亚洲一卡2卡3卡4卡乱码 在线| 亚洲日本乱码在线观看| 国产gv天堂亚洲国产gv刚刚碰| 国产卡二卡三卡四卡免费网址| 一级做a毛片免费视频| 一级一级一级毛片免费毛片| www成人免费视频|