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

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

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

    天天看海

    每天都想看海

    一個(gè)能夠證明i++在多線程下非原子化的例子及其改進(jìn)

    主程序運(yùn)行1000個(gè)子線程(太少了結(jié)果不容易出來),每個(gè)子線程執(zhí)行指向同一整數(shù)引用的i++,當(dāng)1000個(gè)子線程運(yùn)行完畢后,主線程繼續(xù)運(yùn)行,輸出最終的i值。很顯然,如果最終輸出的結(jié)果i值不等于1000,那么中間i++操作一定被分解了。程序代碼如下:

    【版本一】

    import cn.yuzhe.multi.util.AllFinished;

    public class ThreadSafeClass {

    public static void main(String[] args) {
             
    //要?jiǎng)?chuàng)建的子線程數(shù)
                 int threadNum=1000;                          
      
             
    //每個(gè)子線程都要引用的對(duì)象
                 A_Integer bb=new A_Integer();
      
            
    //創(chuàng)建能判斷所有子線程是否結(jié)束的對(duì)象,用于保證主線程能在多有子線程都結(jié)束后再執(zhí)行余下的代碼,
                 
    //防止主線程提前于子線程結(jié)束
                 AllFinished af=new AllFinished(threadNum);  
      
             
    //創(chuàng)建多個(gè)子線程對(duì)象
                 NoAtomicIntegerThread[] at=new NoAtomicIntegerThread[threadNum];
      
                 
    for(int i=0;i<threadNum;i++){
                       at[i]
    =new NoAtomicIntegerThread(bb,i,af);
                 }

      
                 
    for(int i=0;i<threadNum;i++){
                       at[i].start();
                 }
     
      
                 
    while(true){
                       
    if( af.isAllFinished() ){
                             System.out.println(
    "主線程運(yùn)行結(jié)束,應(yīng)該獲得的最終值為"+threadNum
                                              
    +";實(shí)際最終值為"+bb.int_I);
                             
    break;
                       }

       
                      
    int sleep=500;    //睡眠一段時(shí)間,釋放時(shí)間片
                      try {
                            Thread.sleep(sleep);
                      }
     catch (InterruptedException e) {
                            e.printStackTrace();
                      }

                 }
     
             }

    }


    class NoAtomicIntegerThread extends Thread{
              
    public A_Integer jj;
              
    private int id;
              
    private AllFinished af;

    public void run() {
                 jj.int_I
    ++;
                 af.setItemFinished(id);
    //           System.out.println(jj.int_I);              //輸出中間結(jié)果
    }


    public NoAtomicIntegerThread(A_Integer __j,int _id,AllFinished _af) {
                 
    super();
                 
    this.jj=__j;
                 
    this.id=_id;
                 
    this.af=_af;
    }

    }


    class A_Integer
    {
                
    public int int_I=0;
    }



    這里要用到一個(gè)我自己定義的util類:

    /**
    @author 紅樓無夢(mèng),JAVA多線程QQ群:34237757
    * Date:2008-8-13 09:28
    * Function: 主線程創(chuàng)建多個(gè)分線程,保證主線程在所有分線程都結(jié)束后才能運(yùn)行余下的代碼,直至結(jié)束。
    */

    public class AllFinished {
                
    private boolean[] isItemsFinished;
                
    private int num;

                
    public AllFinished(int itemNum) {
                      
    super();
      
                      num
    =itemNum;
                      isItemsFinished
    =new boolean[num];
                      
    for(int i=0;i<num;i++)
                            isItemsFinished[i]
    =false;
                }


                
    public synchronized boolean setItemFinished(int i)
                
    {
                      
    if(i>=num)
                            
    return false;
                      
    this.isItemsFinished[i]=true;
                      
    return true;
                }


                
    public synchronized boolean isAllFinished()
                
    {
                      
    for(int i=0;i<num;i++){
                            
    if(!this.isItemsFinished[i])
                                  
    return false;
                      }

                      
    return true;
                }

    }


    例子需要運(yùn)行多次才能看到結(jié)果,當(dāng)實(shí)際結(jié)果和理想結(jié)果不一樣的時(shí)候,很顯然,i++被分解了,結(jié)果的部分輸入如下:
    ......
    996
    997
    998
    主線程運(yùn)行結(jié)束,應(yīng)該獲得的最終值為1000;實(shí)際最終值為998。

    =====================================================
    【改進(jìn)一】下面的代碼用AtomicInteger進(jìn)行了改進(jìn),使得i++操作被原子化,代碼如下:

    public class ThreadSafeClass {

              
    public static void main(String[] args) {
          
    //要?jiǎng)?chuàng)建的子線程數(shù)
              int threadNum=1000;                          
      
          
    //每個(gè)子線程都要引用的對(duì)象
              AtomicInteger bb=new AtomicInteger(0);
      
          
    //創(chuàng)建能判斷所有子線程是否結(jié)束的對(duì)象,用于保證主線程能在多有子線程都結(jié)束后再執(zhí)行余下的代碼,
              
    //防止主線程提前于子線程結(jié)束
              AllFinished af=new AllFinished(threadNum);  
      
          
    //多個(gè)子線程對(duì)象
              AtomicIntegerThread[] at=new AtomicIntegerThread[threadNum];
      
              
    for(int i=0;i<threadNum;i++){
                   at[i]
    =new AtomicIntegerThread(bb,i,af);
              }

      
              
    for(int i=0;i<threadNum;i++){
                   at[i].start();
              }
     
      
              
    while(true){
                   
    if(af.isAllFinished()){
                        System.out.println(
    "主線程運(yùn)行結(jié)束,應(yīng)該獲得的最終值為"+threadNum
                                                  
    +";實(shí)際最終值為"+bb);
                    
    break;
                   }

       
                   
    int sleep=(int)(Math.random()*500);
                   
    try {
                        Thread.sleep(sleep);
                   }
     catch (InterruptedException e) {
                        e.printStackTrace();
                   }

              }
     
    }

    }


    class AtomicIntegerThread extends Thread{
            
    private int id;
            
    private AllFinished af;
            
    public AtomicInteger j;

             
    public AtomicIntegerThread(AtomicInteger __j,int _id,AllFinished _af) {
                  
    super();
                  
    this.j=__j;
                  
    this.id=_id;
                  
    this.af=_af;
             }



             
    public void run() 
                    j.getAndIncrement();
                   af.setItemFinished(id);
                   System.out.println(j); 
    //這里輸出沒有同步,很可能會(huì)出現(xiàn)不一致,這里僅僅用來測(cè)試一下,正好能證明線程將操作分解^_^   
             }

    }



    運(yùn)行了多次沒有出現(xiàn)被分解的情況,最后我把線程數(shù)從一千改成一萬,又增加到十萬,并且運(yùn)行多次,沒有出現(xiàn)結(jié)果和預(yù)計(jì)結(jié)果不一致的情況。十萬個(gè)線程啊!如果能分解的話早把程序分得七零八碎了,呵呵。某次結(jié)果如下:
    ......
    99994
    99993
    99992
    主線程運(yùn)行結(jié)束,應(yīng)該獲得的最終值為100000;實(shí)際最終值為100000
    =====================================================
    【改進(jìn)二】群友TITAN的方法更簡(jiǎn)單,在版本一的基礎(chǔ)上加上一小段代碼

    class NoAtomicIntegerThread extends Thread{


          
    public void run() {
              
    synchronized(jj){
                        jj.int_I
    ++;
              }

                af.setItemFinished(id);
                System.out.println(jj.int_I);
    }



    }



    我對(duì)比了一下改進(jìn)一和改進(jìn)二,在十萬個(gè)線程并發(fā)情況下,二者的運(yùn)行速度幾乎沒有差別。可見JAVA類庫中的AtomicInteger還是很實(shí)用的。

    大伙有什么改進(jìn)的方法,歡迎大家提意見。yuzhe80@126.com

    ******************************************************************************
    后話:這里為了保證主線程在子線程都執(zhí)行完后再繼續(xù)執(zhí)行,特意定義了一個(gè)類AllFinished,記錄每個(gè)子線程是否結(jié)束,其實(shí)大可不必,因?yàn)镴AVA中對(duì)線程有join函數(shù),在main函數(shù)中改成這樣就可以了。

    public class ThreadSafeClass {
           
    public static void main(String[] args) {
          
    //要?jiǎng)?chuàng)建的子線程數(shù)
           int threadNum=1000;                          
      
          
    //每個(gè)子線程都要引用的對(duì)象
           AtomicInteger bb=new AtomicInteger(0);
      
          
    //多個(gè)子線程對(duì)象
           AtomicIntegerThread[] at=new AtomicIntegerThread[threadNum];
      
           
    for(int i=0;i<threadNum;i++){
                at[i]
    =new AtomicIntegerThread(bb,i);
           }

      
           
    long last=System.currentTimeMillis();
           
    for(int i=0;i<threadNum;i++){
                at[i].start();
           }
     
      
           
    for(int i=0;i<threadNum;i++){
                
    try {
                     at[i].join();                                     
    //保證主線程在所有子線程結(jié)束后再執(zhí)行
                }
     catch (InterruptedException e) {
                     e.printStackTrace();
                }

           }
     
      
           System.out.println(
    "主線程運(yùn)行結(jié)束,應(yīng)該獲得的最終值為"+threadNum
           
    +";實(shí)際最終值為"+bb+"程序運(yùn)行時(shí)間"+(System.currentTimeMillis()-last)+"毫秒");

          }

    }



    而且這樣修改,在性能上有很大提升,用我自定義的類AllFinished,運(yùn)行1000個(gè)線程,平均時(shí)間為2100ms,而用join函數(shù),平均時(shí)間為1600ms,性能提升了25%。以后還是推薦大伙使用join吧^_^

    posted on 2007-08-13 16:56 天天看海 閱讀(376) 評(píng)論(0)  編輯  收藏


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


    網(wǎng)站導(dǎo)航:
     
    <2025年5月>
    27282930123
    45678910
    11121314151617
    18192021222324
    25262728293031
    1234567

    導(dǎo)航

    統(tǒng)計(jì)

    留言簿

    文章檔案

    搜索

    最新評(píng)論

    主站蜘蛛池模板: 亚洲国产美女在线观看| 免费观看激色视频网站(性色)| 偷自拍亚洲视频在线观看99| 亚洲综合色一区二区三区| 亚洲一区二区三区播放在线 | 亚洲精品无码AV中文字幕电影网站| 国产精品冒白浆免费视频| 青青青国产在线观看免费 | 国产亚洲3p无码一区二区| 亚洲成AⅤ人影院在线观看| 日本特黄特色aa大片免费| 韩国免费一级成人毛片| 国产精品视频免费观看| 99精品视频在线免费观看| 青青青国产手机频在线免费观看 | 国产精品亚洲一区二区三区在线| 亚洲国产精品专区在线观看| 国产免费人成视频在线观看| 又爽又黄无遮挡高清免费视频 | 一级做a爰全过程免费视频| 成人免费区一区二区三区| 国产成人无码免费网站| 一级一片免费视频播放| 一级人做人a爰免费视频| 人妖系列免费网站观看| 国产精品美女免费视频观看| 国产成人无码精品久久久免费 | 在线视频免费观看高清| 亚洲免费在线视频播放| 在线看片免费人成视久网| 秋霞人成在线观看免费视频| 久久久久久成人毛片免费看| 久久成人免费电影| 日韩精品人妻系列无码专区免费 | 亚洲免费观看网站| 亚洲日本中文字幕天天更新| 亚洲AV无码一区二区三区电影| 国产亚洲综合视频| 一级女人18片毛片免费视频| 在线观看免费视频一区| 日本视频在线观看永久免费|