<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)

    隨筆檔案

    學習網站

    搜索

    最新評論

    閱讀排行榜

    評論排行榜

    主站蜘蛛池模板: 97se亚洲国产综合自在线| 亚洲视频日韩视频| 精品久久久久亚洲| 国产精品免费视频网站| 无码色偷偷亚洲国内自拍| 日韩一区二区三区免费体验| 亚洲高清一区二区三区| 成人性生交大片免费看无遮挡| 亚洲三级中文字幕| 日本免费网站观看| 猫咪免费人成在线网站| 亚洲国产午夜福利在线播放| 一级毛片免费视频网站| 亚洲乳大丰满中文字幕| 久久精品免费观看国产| 亚洲黄色三级视频| 成人人观看的免费毛片| 美女被免费网站在线视频免费 | 夜夜爽妓女8888视频免费观看| 国产大片91精品免费看3| a级毛片免费高清视频| 国产亚洲av片在线观看16女人| 6080午夜一级毛片免费看 | 国产成人亚洲精品| 免费大黄网站在线看| 中国好声音第二季免费播放| 亚洲国产精品免费视频| 最近最新中文字幕完整版免费高清| 亚洲欧美精品午睡沙发| 亚洲精品无码久久不卡| 无码一区二区三区免费| 亚洲国产精品无码中文lv| 亚洲一级特黄大片无码毛片| 日韩免费高清大片在线| 亚洲av无码一区二区三区天堂| 亚洲伊人久久综合中文成人网| 少妇太爽了在线观看免费视频| 亚洲综合成人婷婷五月网址| 亚洲欧洲精品成人久久奇米网| 国产午夜免费高清久久影院| 亚洲日韩国产二区无码|