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號票。形成這種狀況的緣由是一、a線程和b線程在ticket=7的時候,a線程取出7號票之後,ticket還沒來的及減1b線程就取出了ticket此時ticket還等於7;二、在ticket=1時,b線程取出了1號票,ticket還沒來的及減1,a、c線程就前後進入了if判斷語句,這時ticket減1了,那麼當a、c線程取票的時候就取到了0號和-1號票。
出現了上述狀況怎樣改變呢,咱們能夠這樣作: 當一個線程要使用火車票這個資源時,咱們就交給它一把鎖,等它把事情作完後在把鎖給另外一個要用這個資源的線程。這樣就不會出現上述狀況。 實現這個鎖的功能就須要用到 synchronized這個關鍵字。
synchronized這個關鍵字有兩種用法一、放方法名前造成同步方法;二、放在塊前構成同步塊。
一、使用同步方法將上面的例子該爲:
 
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  
二、使用同步塊修改上面的例子:
 
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:
 
程序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的輸出結果:
ticket4  
程序2的輸出結果看起來並無什麼錯誤,它沒有輸出0和-1號票,可是它沒有實現多個窗口售票的功能,它只有一個窗口在售票,緣由是咱們把鎖放錯了位置。一旦cpu將時間片分給一個線程,那麼這個窗口就必須把全部的票賣完。
鑑於以上兩種錯誤程序致使的結果,筆者建議你們使用同步方法這種方法比較方便。
關於生產者和消費者的問題,請參看「 模擬生產零件系統程序」。
相關文章
相關標籤/搜索