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

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

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

    把困難踩在腳下

    迎難而上

     

    java 同步鎖(synchronized)

    java中cpu分給每個線程的時間片是隨機的并且在java中好多都是多個線程共用一個資源,比如火車賣票,火車票是一定的,但賣火車票的窗口到處都有,每個窗口就相當于一個線程,這么多的線程共用所有的火車票這個資源。如果在一個時間點上,兩個線程同時使用這個資源,那他們取出的火車票是一樣的(座位號一樣),這樣就會給乘客造成麻煩。比如下面程序:

     

    package com.dr.runnable2;
    class TicketSouce implements Runnable
    {
        
    //票的總數
        private int ticket=10;
        
    public void run()
        
    {
            
    for(int i=1;i<50;i++)
            
    {
                
    if(ticket>0)
                
    {
                    
    //休眠1s秒中,為了使效果更明顯,否則可能出不了效果
                    try {
                        Thread.sleep(
    1000);
                    }
     catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                    System.out.println(Thread.currentThread().getName()
    +"號窗口賣出"+this.ticket--+"號票");
                }

            }

        }

    }

    public class Test {
        
    public static void main(String args[])
        
    {
            TicketSouce mt
    =new TicketSouce();
            
    //基于火車票創建三個窗口
            new Thread(mt,"a").start();
            
    new Thread(mt,"b").start();
            
    new Thread(mt,"c").start();
        }
     

    }
     

     

    程序的運行結果是:

    ticket

    我們可以看到a號窗口和和c號窗口都賣出了7號票,并且a號和c號窗口分別賣出了0號和-1號票。造成這種情況的原因是1、a線程和b線程在ticket=7的時候,a線程取出7號票以后,ticket還沒來的及減1b線程就取出了ticket此時ticket還等于7;2、在ticket=1時,b線程取出了1號票,ticket還沒來的及減1,a、c線程就先后進入了if判斷語句,這時ticket減1了,那么當a、c線程取票的時候就取到了0號和-1號票。

    出現了上述情況怎樣改變呢,我們可以這樣做:當一個線程要使用火車票這個資源時,我們就交給它一把鎖,等它把事情做完后在把鎖給另一個要用這個資源的線程。這樣就不會出現上述情況。 實現這個鎖的功能就需要用到synchronized這個關鍵字。

    synchronized這個關鍵字有兩種用法1、放方法名前形成同步方法;2、放在塊前構成同步塊。

    1、使用同步方法將上面的例子該為:

     

    package com.dr.runnable2;
    class TicketSouce implements Runnable
    {
        
    //票的總數
        private int ticket=10;
        
    public void run()
        
    {
            
    for(int i=1;i<50;i++)
            
    {
                
    try {
                    
    //休眠1s秒中,為了使效果更明顯,否則可能出不了效果
                    Thread.sleep(1000);
                }
     catch (InterruptedException e) {
                    e.printStackTrace();
                }

                
    this.sale();
            }

        }

        
    public synchronized void sale()
        
    {
                
    if(ticket>0)
                
    {
                    System.out.println(Thread.currentThread().getName()
    +"號窗口賣出"+this.ticket--+"號票");
                }

        }

    }

    public class Test {
        
    public static void main(String args[])
        
    {
            TicketSouce mt
    =new TicketSouce();
            
    //基于火車票創建三個窗口
            new Thread(mt,"a").start();
            
    new Thread(mt,"b").start();
            
    new Thread(mt,"c").start();
        }
     

    }
     

    程序的輸出結果為:

    ticket1

    2、使用同步塊修改上面的例子:

     

    package com.dr.runnable2;
    class TicketSouce implements Runnable
    {
        
    //票的總數
        private int ticket=10;
        
    public void run()
        
    {
            
    for(int i=1;i<50;i++)
            
    {
                
    synchronized(this){
                    
    if(ticket>0)
                    
    {
                        
    //休眠1s秒中,為了使效果更明顯,否則可能出不了效果
                        try {
                            Thread.sleep(
    1000);
                        }
     catch (InterruptedException e) {
                            e.printStackTrace();
                        }

                        System.out.println(Thread.currentThread().getName()
    +"號窗口賣出"+this.ticket--+"號票");
                    }

                                  }

            }

        }

    }

    public class Test {
        
    public static void main(String args[])
        
    {
            TicketSouce mt
    =new TicketSouce();
            
    //基于火車票創建三個窗口
            new Thread(mt,"a").start();
            
    new Thread(mt,"b").start();
            
    new Thread(mt,"c").start();
        }
     

    }
     

    程序的輸出結果:

    ticket2

    上面的情況是正確的,我在調試程序的時候把synchronized放錯了位置導致了錯誤的結果,我們來看一下錯誤的原因:

    程序1:

     

    package com.dr.runnable2;
    class TicketSouce implements Runnable
    {
        
    //票的總數
        private int ticket=10;
        
    public void run()
        
    {
            
    for(int i=1;i<50;i++)
            
    {
                
    if(ticket>0)
                
    synchronized(this){
                    
    //休眠1s秒中,為了使效果更明顯,否則可能出不了效果
                    try {
                        Thread.sleep(
    1000);
                    }
     catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                    System.out.println(Thread.currentThread().getName()
    +"號窗口賣出"+this.ticket--+"號票");
                                   }

            }

        }

    }

    public class Test {
        
    public static void main(String args[])
        
    {
            TicketSouce mt
    =new TicketSouce();
            
    //基于火車票創建三個窗口
            new Thread(mt,"a").start();
            
    new Thread(mt,"b").start();
            
    new Thread(mt,"c").start();
        }
     

    }
     

    程序1的運行結果:

     ticket3

    程序1的輸出結果竟然出了0號和-1號票,原因就是synchronized放錯了位置,程序1將synchronized放在了if語句的后面,當b線程取出2好票以后,此時ticket=1,等下一次a、b、c線程來的時候,ticket=1>0就進入if語句體,這時cpu分給線程的時間片是先b在c后a這樣就導致了上面的結果。

    程序2:

     

    package com.dr.runnable2;
    class TicketSouce implements Runnable
    {
        
    //票的總數
        private int ticket=10;
        
    public void run()
        
    {
            
    synchronized(this){
                
    for(int i=1;i<50;i++)
                
    {
                    
    if(ticket>0)
                    
    {
                        
    //休眠1s秒中,為了使效果更明顯,否則可能出不了效果
                        try {
                            Thread.sleep(
    1000);
                        }
     catch (InterruptedException e) {
                            e.printStackTrace();
                        }

                        System.out.println(Thread.currentThread().getName()
    +"號窗口賣出"+this.ticket--+"號票");
                     }

                }
     

                               }

                }

    }

    public class Test {
        
    public static void main(String args[])
        
    {
            TicketSouce mt
    =new TicketSouce();
            
    //基于火車票創建三個窗口
            new Thread(mt,"a").start();
            
    new Thread(mt,"b").start();
            
    new Thread(mt,"c").start();
        }
     

    }
     

    程序2的輸出結果:

    ticket4

    程序2的輸出結果看起來并沒有什么錯誤,它沒有輸出0和-1號票,但是它沒有實現多個窗口售票的功能,它只有一個窗口在售票,原因是我們把鎖放錯了位置。一旦cpu將時間片分給一個線程,那么這個窗口就必須把所有的票賣完。

    鑒于以上兩種錯誤程序導致的結果,筆者建議大家使用同步方法這種方法比較方便。
    關于生產者和消費者的問題,請參看“模擬生產零件系統程序”。

    posted on 2010-11-10 13:48 馮魁 閱讀(66049) 評論(11)  編輯  收藏

    評論

    # re: java 同步鎖(synchronized) 2012-10-29 15:46 eagledame

    兄弟 是不是搞錯了啊
    a號窗口 ,售出20號車票
    a號窗口 ,售出19號車票
    a號窗口 ,售出18號車票
    a號窗口 ,售出17號車票
    a號窗口 ,售出16號車票
    a號窗口 ,售出15號車票
    a號窗口 ,售出14號車票
    a號窗口 ,售出13號車票
    a號窗口 ,售出12號車票
    a號窗口 ,售出11號車票
    d號窗口 ,售出10號車票
    d號窗口 ,售出9號車票
    d號窗口 ,售出8號車票
    d號窗口 ,售出7號車票
    d號窗口 ,售出6號車票
    d號窗口 ,售出5號車票
    d號窗口 ,售出4號車票  回復  更多評論   

    # re: java 同步鎖(synchronized) 2012-10-29 15:56 eagledame

    兄弟 我執行了你的程序1 和程序2 結果如上 。和你說的完全不一樣 。求解釋   回復  更多評論   

    # re: java 同步鎖(synchronized) 2012-12-11 17:30 游客

    賣完票 記得ticket--  回復  更多評論   

    # re: java 同步鎖(synchronized) 2013-03-26 16:08 馬容亮

    我的理解 是java默認多線程,但是 多線程并發會導致 公用變量處理不準確,synchronized 同步 使 每個線程處理公用變量時,能夠在一個完善的隊列中完成。  回復  更多評論   

    # re: java 同步鎖(synchronized) 2014-06-05 01:04

    @eagledame
    把值設置大點兒  回復  更多評論   

    # re: java 同步鎖(synchronized) 2014-08-16 11:32 文宇

    程序一和程序二都可以多窗口售票,只是票的總數不夠大,沒有等到b,c線程執行,當ticket=1000時,就可以看到  回復  更多評論   

    # re: java 同步鎖(synchronized)[未登錄] 2014-10-08 09:16 秋風

    寫得太好了,謝謝作者對人類軟件事業進步所做出的重大貢獻  回復  更多評論   

    # re: java 同步鎖(synchronized) 2014-10-13 11:14 zyongsh

    java線程調度是隨機的,即使統一程序在同一臺java虛擬機上執行的結果也可能會不同@eagledame
      回復  更多評論   

    # re: java 同步鎖(synchronized) 2014-11-28 10:18 家樂

    public void run()
    {
    while (true)
    {
    synchronized (this)
    {
    if (ticket > 0)
    {
    System.out.println(Thread.currentThread().getName() + "號窗口賣出" + this.ticket-- + "號票");
    }
    else
    {
    System.out.println(Thread.currentThread().getName() + "票已售完");
    break;
    }
    }
    try
    {
    Thread.sleep(1000);
    }
    catch (InterruptedException e)
    {
    e.printStackTrace();
    }
    }
    }  回復  更多評論   

    # re: java 同步鎖(synchronized)[未登錄] 2015-07-29 15:04 111

    你這個不算是多線程的同步吧
      回復  更多評論   

    # re: java 同步鎖(synchronized) 2015-07-29 18:40 龍井

    2、使用同步塊修改上面的例子修改錯誤的,正確如下:
    public void run()
    {
    for(int i=1;i<50;i++)
    {
    //休眠1s秒中,為了使效果更明顯,否則可能出不了效果
    try {
    Thread.sleep(1000);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    synchronized(this){
    if(ticket>0)
    {
    System.out.println(Thread.currentThread().getName()+"號窗口賣出"+this.ticket--+"號票");
    }
    }
    }
    }  回復  更多評論   


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


    網站導航:
     

    導航

    統計

    公告

    快樂每一天!

    Everything is an object!

    常用鏈接

    留言簿(2)

    隨筆檔案

    學習網站

    搜索

    最新評論

    閱讀排行榜

    評論排行榜

    主站蜘蛛池模板: 亚洲AV无码久久| 成人片黄网站色大片免费观看APP| 中文字幕亚洲乱码熟女一区二区 | 日韩精品内射视频免费观看| 黄网站色视频免费观看45分钟| 亚洲免费在线观看视频| 亚洲欧洲日产国码无码久久99| 国产又粗又猛又爽又黄的免费视频 | 一区二区在线视频免费观看| 亚洲 暴爽 AV人人爽日日碰| 亚洲国产成人私人影院| 亚洲伊人久久大香线蕉综合图片| 性做久久久久免费看| 好先生在线观看免费播放| 99re6在线精品视频免费播放| 中文字幕免费在线看线人动作大片| 亚洲AV无码一区二区三区鸳鸯影院| 亚洲AV成人无码天堂| 97久久精品亚洲中文字幕无码 | 最新亚洲卡一卡二卡三新区| 久久久久久亚洲精品成人| 亚洲老妈激情一区二区三区| 亚洲福利在线播放| 国产男女猛烈无遮档免费视频网站| 欧美好看的免费电影在线观看| 四虎在线最新永久免费| 7m凹凸精品分类大全免费| 久久er国产精品免费观看2| 99精品免费视品| 男女一边摸一边做爽的免费视频| 午夜成人无码福利免费视频| 猫咪免费人成在线网站| 无遮挡a级毛片免费看| 免费精品国自产拍在线播放| 免费人成视频在线观看免费| 白白色免费在线视频| 黄色毛片免费观看| 大片免费观看92在线视频线视频| 免费无码国产在线观国内自拍中文字幕| 99亚洲男女激情在线观看| 免费在线观看亚洲|