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

    隨筆檔案

    學習網站

    搜索

    最新評論

    閱讀排行榜

    評論排行榜

    主站蜘蛛池模板: 永久看日本大片免费35分钟| 99久久免费国产精品热| 亚欧免费视频一区二区三区| 亚洲VA中文字幕无码一二三区| 亚洲精品美女久久久久9999| 在线日本高清免费不卡| 亚洲成人免费网站| 日韩一区二区a片免费观看 | 成人免费视频试看120秒| 中文字幕无码亚洲欧洲日韩| 思思99re66在线精品免费观看| 亚洲大片免费观看| 久久不见久久见免费影院| 亚洲av午夜国产精品无码中文字| 无码人妻一区二区三区免费| 亚洲精品国产高清在线观看| 国产资源免费观看| 国产精品无码素人福利免费| 鲁死你资源站亚洲av| 亚洲成AV人网址| 免费成人高清在线视频| 亚洲午夜电影在线观看| 久久免费线看线看| 亚洲国产成人精品无码一区二区| 久操免费在线观看| 在线精品亚洲一区二区| 亚洲精品动漫免费二区| 色屁屁在线观看视频免费| 久久久久久久尹人综合网亚洲| 久久精品免费一区二区三区| 亚洲av永久无码嘿嘿嘿| mm1313亚洲国产精品美女| 色综合久久精品亚洲国产| 久久久久久A亚洲欧洲AV冫| 日本免费人成视频在线观看| 亚洲精华国产精华精华液网站 | 四虎影院免费在线播放| 二个人看的www免费视频| 亚洲国产日韩在线一区| 亚洲国产成人精品女人久久久 | 亚洲AV成人精品网站在线播放|