欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java線程同步機(jī)制_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

 更新時(shí)間:2017年05月26日 15:52:37   投稿:mrr  
在之前,已經(jīng)學(xué)習(xí)到了線程的創(chuàng)建和狀態(tài)控制,但是每個(gè)線程之間幾乎都沒(méi)有什么太大的聯(lián)系。可是有的時(shí)候,可能存在多個(gè)線程多同一個(gè)數(shù)據(jù)進(jìn)行操作,這樣,可能就會(huì)引用各種奇怪的問(wèn)題?,F(xiàn)在就來(lái)學(xué)習(xí)多線程對(duì)數(shù)據(jù)訪問(wèn)的控制吧

在之前,已經(jīng)學(xué)習(xí)到了線程的創(chuàng)建和狀態(tài)控制,但是每個(gè)線程之間幾乎都沒(méi)有什么太大的聯(lián)系??墒怯械臅r(shí)候,可能存在多個(gè)線程多同一個(gè)數(shù)據(jù)進(jìn)行操作,這樣,可能就會(huì)引用各種奇怪的問(wèn)題。現(xiàn)在就來(lái)學(xué)習(xí)多線程對(duì)數(shù)據(jù)訪問(wèn)的控制吧。

由于同一進(jìn)程的多個(gè)線程共享同一片存儲(chǔ)空間,在帶來(lái)方便的同時(shí),也帶來(lái)了訪問(wèn)沖突這個(gè)嚴(yán)重的問(wèn)題。Java語(yǔ)言提供了專(zhuān)門(mén)機(jī)制以解決這種沖突,有效避免了同一個(gè)數(shù)據(jù)對(duì)象被多個(gè)線程同時(shí)訪問(wèn)。

一、多線程引起的數(shù)據(jù)訪問(wèn)安全問(wèn)題

下面看一個(gè)經(jīng)典的問(wèn)題,銀行取錢(qián)的問(wèn)題:

1)、你有一張銀行卡,里面有5000塊錢(qián),然后你到取款機(jī)取款,取出3000,當(dāng)正在取的時(shí)候,取款機(jī)已經(jīng)查詢(xún)到你有5000塊錢(qián),然后正準(zhǔn)備減去300塊錢(qián)的時(shí)候

2)、你的老婆拿著那張銀行卡對(duì)應(yīng)的存折到銀行取錢(qián),也要取3000.然后銀行的系統(tǒng)查詢(xún),存折賬戶(hù)里還有6000(因?yàn)樯厦驽X(qián)還沒(méi)扣),所以它也準(zhǔn)備減去3000,

3)、你的卡里面減去3000,5000-3000=2000,并且你老婆的存折也是5000-3000=2000。

4)、結(jié)果,你們一共取了6000,但是卡里還剩下2000。

下面看程序的模擬過(guò)程:

package com.bjpowernode.test; 
 public class GetMoneyTest { 
   public static void main(String[] args) { 
     Account account = new Account(5000); 
     GetMoneyRun runnable = new GetMoneyRun(account); 
     new Thread(runnable, "你").start(); 
     new Thread(runnable, "你老婆").start(); 
   } 
 } 
 // 賬戶(hù)Mode 
 class Account { 
   private int money; 
   public Account(int money) { 
     super(); 
     this.money = money; 
   } 
   public int getMoney() { 
     return money; 
   } 
   public void setMoney(int money) { 
     this.money = money; 
   } 
 } 
 //runnable類(lèi) 
 class GetMoneyRun implements Runnable { 
   private Account account; 
   public GetMoneyRun(Account account) { 
     this.account = account; 
   } 
   @Override 
   public void run() { 
     if (account.getMoney() > 3000) { 
       System.out.println(Thread.currentThread().getName() + "的賬戶(hù)有" 
           + account.getMoney() + "元"); 
       try { 
         Thread.sleep(10); 
       } catch (InterruptedException e) { 
         e.printStackTrace(); 
       } 
       int lasetMoney=account.getMoney() - 3000; 
       account.setMoney(lasetMoney); 
       System.out.println(Thread.currentThread().getName() + "取出來(lái)了3000元" 
           + Thread.currentThread().getName() + "的賬戶(hù)還有" 
           + account.getMoney() + "元"); 
     } else { 
       System.out.println("余額不足3000" + Thread.currentThread().getName() 
           + "的賬戶(hù)只有" + account.getMoney() + "元"); 
     } 
   } 
 } 

多次運(yùn)行程序,可以看到有多種不同的結(jié)果,下面是其中的三種:

1. 你的賬戶(hù)有5000元 
2. 你老婆的賬戶(hù)有5000元 
3. 你老婆取出來(lái)了3000元你老婆的賬戶(hù)還有2000元 
4. 你取出來(lái)了3000元你的賬戶(hù)還有-1000元 

1. 你的賬戶(hù)有5000元 
2. 你老婆的賬戶(hù)有5000元 
3. 你老婆取出來(lái)了3000元你老婆的賬戶(hù)還有-1000元 
4. 你取出來(lái)了3000元你的賬戶(hù)還有-1000元 

1. 你的賬戶(hù)有5000元 
2. 你老婆的賬戶(hù)有5000元 
3. 你老婆取出來(lái)了3000元你老婆的賬戶(hù)還有2000元 
4. 你取出來(lái)了3000元你的賬戶(hù)還有2000元 

可以看到,由于有兩個(gè)線程同時(shí)訪問(wèn)這個(gè)account對(duì)象,導(dǎo)致取錢(qián)發(fā)生的賬戶(hù)發(fā)生問(wèn)題。當(dāng)多個(gè)線程訪問(wèn)同一個(gè)數(shù)據(jù)的時(shí)候,非常容易引發(fā)問(wèn)題。為了避免這樣的事情發(fā)生,我們要保證線程同步互斥,所謂同步互斥就是:并發(fā)執(zhí)行的多個(gè)線程在某一時(shí)間內(nèi)只允許一個(gè)線程在執(zhí)行以訪問(wèn)共享數(shù)據(jù)。

二、同步互斥鎖

同步鎖的原理:Java中每個(gè)對(duì)象都有一個(gè)內(nèi)置同步鎖。Java中可以使用synchronized關(guān)鍵字來(lái)取得一個(gè)對(duì)象的同步鎖。synchronized的使用方式,是在一段代碼塊中,加上synchronized(object){ ... }
例如,有一個(gè)show方法,里面有synchronized的代碼段:

 public void show() { 
   synchronized(object){ 
    ...... 
   } 
 } 

這其中的object可以使任何對(duì)象,表示當(dāng)前線程取得該對(duì)象的鎖。一個(gè)對(duì)象只有一個(gè)鎖,所以其他任何線程都不能訪問(wèn)該對(duì)象的所有由synchronized包括的代碼段,直到該線程釋放掉這個(gè)對(duì)象的同步鎖(釋放鎖是指持鎖線程退出了synchronized同步方法或代碼塊)。

注意:synchronized使用方式有幾個(gè)要注意的地方(還是以上面的show方法舉例):

①、取得同步鎖的對(duì)象為this,即當(dāng)前類(lèi)對(duì)象,這是使用的最多的一種方式

 public void show() { 
   synchronized(this){ 
    ...... 
   } 
 } 

②、將synchronized加到方法上,這叫做同步方法,相當(dāng)于第一種方式的縮寫(xiě)

 public synchronized void show() { 
   
 } 

③、靜態(tài)方法的同步

 public static synchronized void show() { 
 } 

相當(dāng)于

 public static void show() { 
  synchronized(當(dāng)前類(lèi)名.class)  
 } 

相當(dāng)于取得類(lèi)對(duì)象的同步鎖,注意它和取得一個(gè)對(duì)象的同步鎖不一樣

明白了同步鎖的原理和synchronized關(guān)鍵字的使用,那么解決上面的取錢(qián)問(wèn)題就很簡(jiǎn)單了,我們只要對(duì)run方法里面加上synchronized關(guān)鍵字就沒(méi)有問(wèn)題了,如下:

 @Override 
   public void run() { 
     synchronized (account) { 
       if (account.getMoney() > 3000) { 
         System.out.println(Thread.currentThread().getName() + "的賬戶(hù)有" 
             + account.getMoney() + "元"); 
         try { 
           Thread.sleep(10); 
         } catch (InterruptedException e) { 
           e.printStackTrace(); 
         } 
         int lasetMoney = account.getMoney() - 3000; 
         account.setMoney(lasetMoney); 
         System.out.println(Thread.currentThread().getName() 
             + "取出來(lái)了3000元" + Thread.currentThread().getName() 
             + "的賬戶(hù)還有" + account.getMoney() + "元"); 
  
       } else { 
         System.out.println("余額不足3000" 
             + Thread.currentThread().getName() + "的賬戶(hù)只有" 
             + account.getMoney() + "元"); 
       } 
     } 
   } 

當(dāng)甲線程執(zhí)行run方法的時(shí)候,它使用synchronized (account)取得了account對(duì)象的同步鎖,那么只要它沒(méi)釋放掉這個(gè)鎖,那么當(dāng)乙線程執(zhí)行到run方法的時(shí)候,它就不能獲得繼續(xù)執(zhí)行的鎖,所以只能等甲線程執(zhí)行完,然后釋放掉鎖,乙線程才能繼續(xù)執(zhí)行。

synchronized關(guān)鍵字使用要注意以下幾點(diǎn):

1)、只能同步方法和代碼塊,而不能同步變量和類(lèi)。只要保護(hù)好類(lèi)中數(shù)據(jù)的安全訪問(wèn)和設(shè)置就可以了,不需要對(duì)類(lèi)使用synchronized關(guān)鍵字,所以Java不允許這么做。并且想要同步數(shù)據(jù),只需要對(duì)成員變量私有化,然后同步方法即可,不需要對(duì)成員變量使用synchronized,java也禁止這么做。

2)、每個(gè)對(duì)象只有一個(gè)同步鎖;當(dāng)提到同步時(shí),應(yīng)該清楚在什么上同步?也就是說(shuō),在哪個(gè)對(duì)象上同步?上面的代碼中run方法使用synchronized (account)代碼塊,因?yàn)閮蓚€(gè)線程訪問(wèn)的都是同一個(gè)Account對(duì)象,所以能夠鎖定。但是如果是其他的一個(gè)無(wú)關(guān)的對(duì)象,就沒(méi)用了。比如說(shuō)synchronized (new Date())代碼塊,一樣沒(méi)有效果。

3)、不必同步類(lèi)中所有的方法,類(lèi)可以同時(shí)擁有同步和非同步方法。

4)、如果兩個(gè)線程要執(zhí)行一個(gè)類(lèi)中的synchronized方法,并且兩個(gè)線程使用相同的實(shí)例來(lái)調(diào)用方法,那么一次只能有一個(gè)線程能夠執(zhí)行方法,另一個(gè)需要等待,直到鎖被釋放。也就是說(shuō):如果一個(gè)線程在對(duì)象上獲得一個(gè)鎖,就沒(méi)有任何其他線程可以進(jìn)入(該對(duì)象的)類(lèi)中的任何一個(gè)同步方法。

5)、如果線程擁有同步和非同步方法,則非同步方法可以被多個(gè)線程自由訪問(wèn)而不受鎖的限制。

6)、線程睡眠時(shí),它所持的任何同步鎖都不會(huì)釋放。

7)、線程可以獲得多個(gè)同步鎖。比如,在一個(gè)對(duì)象的同步方法里面調(diào)用另外一個(gè)對(duì)象的同步方法,則獲取了兩個(gè)對(duì)象的同步同步鎖。

8)、同步損害并發(fā)性,應(yīng)該盡可能縮小同步范圍。同步不但可以同步整個(gè)方法,還可以同步方法中一部分代碼塊。

9)、編寫(xiě)線程安全的代碼會(huì)使系統(tǒng)的總體效率會(huì)降低,要適量使用

一個(gè)線程取得了同步鎖,那么在什么時(shí)候才會(huì)釋放掉呢?

1、同步方法或代碼塊正常結(jié)束

2、使用return或 break終止了執(zhí)行,或者跑出了未處理的異常。

3、當(dāng)線程執(zhí)行同步方法或代碼塊時(shí),程序執(zhí)行了同步鎖對(duì)象的wait()方法。

三、死鎖

死鎖:多個(gè)線程同時(shí)被阻塞,它們中的一個(gè)或者全部都在等待某個(gè)資源被釋放。由于線程被無(wú)限期地阻塞,因此程序不能正常運(yùn)行。簡(jiǎn)單的說(shuō)就是:線程死鎖時(shí),第一個(gè)線程等待第二個(gè)線程釋放資源,而同時(shí)第二個(gè)線程又在等待第一個(gè)線程釋放資源。這里舉一個(gè)通俗的例子:如在人行道上兩個(gè)人迎面相遇,為了給對(duì)方讓道,兩人同時(shí)向一側(cè)邁出一步,雙方無(wú)法通過(guò),又同時(shí)向另一側(cè)邁出一步,這樣還是無(wú)法通過(guò)。假設(shè)這種情況一直持續(xù)下去,這樣就會(huì)發(fā)生死鎖現(xiàn)象。

    導(dǎo)致死鎖的根源在于不適當(dāng)?shù)剡\(yùn)用“synchronized”關(guān)鍵詞來(lái)管理線程對(duì)特定對(duì)象的訪問(wèn)?!皊ynchronized”關(guān)鍵詞的作用是,確保在某個(gè)時(shí)刻只有一個(gè)線程被允許執(zhí)行特定的代碼塊,因此,被允許執(zhí)行的線程首先必須擁有對(duì)變量或?qū)ο蟮呐潘栽L問(wèn)權(quán)。當(dāng)線程訪問(wèn)對(duì)象時(shí),線程會(huì)給對(duì)象加鎖,而這個(gè)鎖導(dǎo)致其它也想訪問(wèn)同一對(duì)象的線程被阻塞,直至第一個(gè)線程釋放它加在對(duì)象上的鎖。

一個(gè)死鎖的造成很簡(jiǎn)單,比如有兩個(gè)對(duì)象A 和 B 。第一個(gè)線程鎖住了A,然后休眠1秒,輪到第二個(gè)線程執(zhí)行,第二個(gè)線程鎖住了B,然后也休眠1秒,然后有輪到第一個(gè)線程執(zhí)行。第一個(gè)線程又企圖鎖住B,可是B已經(jīng)被第二個(gè)線程鎖定了,所以第一個(gè)線程進(jìn)入阻塞狀態(tài),又切換到第二個(gè)線程執(zhí)行。第二個(gè)線程又企圖鎖住A,可是A已經(jīng)被第一個(gè)線程鎖定了,所以第二個(gè)線程也進(jìn)入阻塞狀態(tài)。就這樣,死鎖造成了。

舉個(gè)例子:

package com.bjpowernode.test; 
 public class DeadLock2 { 
   public static void main(String[] args) { 
     Object object1=new Object(); 
     Object object2=new Object(); 
     new Thread(new T(object1,object2)).start(); 
     new Thread(new T(object2,object1)).start(); 
   } 
 } 
 class T implements Runnable{ 
   private Object object1; 
   private Object object2; 
   public T(Object object1,Object object2) { 
     this.object1=object1; 
     this.object2=object2; 
   } 
   public void run() { 
     synchronized (object1) { 
       try { 
         Thread.sleep(1000); 
       } catch (InterruptedException e) { 
         e.printStackTrace(); 
       } 
       synchronized (object2) { 
         System.out.println("無(wú)法執(zhí)行到這一步"); 
       } 
     } 
   }; 
 } 

上面的就是個(gè)死鎖。

第一個(gè)線程首先鎖住了object1,然后休眠。接著第二個(gè)線程鎖住了object2,然后休眠。在第一個(gè)線程企圖在鎖住object2,進(jìn)入阻塞。然后第二個(gè)線程企圖在鎖住object1,進(jìn)入阻塞。死鎖了。

四、線程的協(xié)調(diào)運(yùn)行

關(guān)于線程的協(xié)調(diào)運(yùn)行,經(jīng)典的例子就是生產(chǎn)者和消費(fèi)者的問(wèn)題。比如有生產(chǎn)者不斷的生產(chǎn)饅頭,放入一個(gè)籃子里,而消費(fèi)者不斷的從籃子里拿饅頭吃。并且,當(dāng)籃子滿的時(shí)候,生產(chǎn)者通知消費(fèi)者來(lái)吃饅頭,并且自己等待不在生產(chǎn)饅頭。當(dāng)籃子沒(méi)滿的的時(shí)候,由消費(fèi)者通知生產(chǎn)者生產(chǎn)饅頭。這樣不斷的循環(huán)。

要完成上面的功能,光靠我們前面的同步等知識(shí),是不能完成的。而是要用到線程間的協(xié)調(diào)運(yùn)行。頂級(jí)父類(lèi)Object中有3種方法來(lái)控制線程的協(xié)調(diào)運(yùn)行。

notify、notifyAll、wait。其中wait有3個(gè)重載的方法。

這三個(gè)方法必須由同步監(jiān)視器對(duì)象(即線程獲得的鎖對(duì)象)來(lái)調(diào)用,這可分為兩種情況:

1、對(duì)于使用synchronized修飾的同步代碼塊,因?yàn)楫?dāng)前的類(lèi)對(duì)象(this)就是同步監(jiān)視器,所以可以再同步方法中直接調(diào)用這三個(gè)方法。

2、對(duì)于使用synchronized修飾的同步代碼塊,同步監(jiān)視器是synchronized后括號(hào)的對(duì)象,所以必須使用該對(duì)象調(diào)用這三個(gè)方法。

wait(): 導(dǎo)致當(dāng)前線程等待,直到其他線程調(diào)用該同步監(jiān)視器的notify()方法或notifyAll()方法來(lái)喚醒該線程。wait()方法有三種形式:無(wú)時(shí)間參數(shù)的wait(一直等待,直到其他線程通知),帶毫秒?yún)?shù)的wait和帶毫秒、微秒?yún)?shù)的wait(這兩種方法都是等待指定時(shí)間后自動(dòng)蘇醒)。調(diào)用wait()方法的當(dāng)前線程會(huì)釋放對(duì)該同步監(jiān)視器的鎖定。

notify(): 喚醒在此同步監(jiān)視器上等待的單個(gè)線程。如果所有線程都在此同步監(jiān)視器上等待,則會(huì)選擇幻想其中一個(gè)線程。選擇是任意性。只有當(dāng)前線程放棄對(duì)該同步監(jiān)視器的鎖定后(使用wait()方法),才可以執(zhí)行被喚醒的其他線程。

notifyAll():?jiǎn)拘言诖送奖O(jiān)視器上等待的所有線程。只有當(dāng)前線程放棄對(duì)該同步監(jiān)視器的鎖定后,才可以執(zhí)行被喚醒的線程。

因?yàn)槭褂脀ait、notify和notifyAll三個(gè)方法一定是在同步代碼塊中使用的,所以一定要明白下面幾點(diǎn):

1、如果兩個(gè)線程是因?yàn)槎家玫酵粋€(gè)對(duì)象的鎖,而導(dǎo)致其中一個(gè)線程進(jìn)入阻塞狀態(tài)。那么只有等獲得鎖的線程執(zhí)行完畢,或者它執(zhí)行了該鎖對(duì)象的wait方法,阻塞的線程才會(huì)有機(jī)會(huì)得到鎖,繼續(xù)執(zhí)行同步代碼塊。

2、使用wait方法進(jìn)入等待狀態(tài)的線程,會(huì)釋放掉鎖。并且只有其他線程調(diào)用notify或者notifyAll方法,才會(huì)被喚醒。要明白,線程因?yàn)殒i阻塞和等待是不同的,因?yàn)殒i進(jìn)入阻塞狀態(tài),會(huì)在其他線程釋放鎖的時(shí)候,得到鎖在執(zhí)行。而等待狀態(tài)必須要靠別人喚醒,并且喚醒了也不一定會(huì)立刻執(zhí)行,有可能因?yàn)閚otifyAll方法使得很多線程被喚醒,多個(gè)線程等待同一個(gè)鎖,而進(jìn)入阻塞狀態(tài)。還可能是調(diào)用notify的線程依然沒(méi)有釋放掉鎖,只有等他執(zhí)行完了,其他線程才能去爭(zhēng)奪這個(gè)鎖。

看下面的例子:

package com.bjpowernode.test; 
 public class ThreadA { 
   public static void main(String[] args) { 
     RunnableTest myRunnanle=new RunnableTest(); 
    new Thread(myRunnanle).start(); 
     synchronized (myRunnanle) { 
       try { 
         System.out.println("第一步"); 
         myRunnanle.wait(); 
       } catch (InterruptedException e) { 
         e.printStackTrace(); 
       } 
       System.out.println("第四步"); 
     } 
   } 
 } 
 class RunnableTest implements Runnable { 
   public void run() { 
     try { 
       Thread.sleep(1); 
     } catch (InterruptedException e) { 
       e.printStackTrace(); 
     } 
     synchronized (this) { 
       System.out.println("第二步"); 
       notify(); 
       System.out.println("第三步"); 
     } 
   } 
 } 

有兩個(gè)線程,主線程和我們自己新建的子線程。一步步的分析程序的執(zhí)行:

1、因?yàn)樽泳€程啟動(dòng)后,調(diào)用了sleep,所以主線程先進(jìn)入同步代碼塊,而子線程之后因?yàn)闆](méi)有鎖,會(huì)進(jìn)入阻塞狀態(tài)。

2、主線程的同步代碼塊執(zhí)行,打印第一句話,然后調(diào)用wait方法,進(jìn)入等待狀態(tài)。因?yàn)檫M(jìn)入了等待狀態(tài),所以釋放掉了鎖,所以子線程可以獲得鎖,開(kāi)始執(zhí)行。

3、子線程執(zhí)行,打印第二句話,然后調(diào)用notify方法,將主線程喚醒。可是子線程并沒(méi)有結(jié)束,依然持有鎖,所以主線程不得不進(jìn)入阻塞狀態(tài),等待這個(gè)鎖。

4、子線程打印第三句話,然后線程正常運(yùn)行結(jié)束,釋放掉鎖。然后主線程得到了鎖,從阻塞進(jìn)入運(yùn)行狀態(tài),打印第四句話。

5、完畢

在看一個(gè)關(guān)于上面提到的生產(chǎn)者和消費(fèi)者的例子:

首先,是生產(chǎn)物品的Mode,這里以饅頭舉例:

 // 饅頭的實(shí)例 
 class ManTou { 
   private int id;// 饅頭的id 
  
   public ManTou(int id) { 
     this.id = id; 
   } 
   public String toString(){ 
     return "ManTou"+id; 
   } 
 } 

共享對(duì)象,生產(chǎn)者生產(chǎn)的饅頭放入其中,消費(fèi)者從里面拿出饅頭,這里以籃子舉例:

// 籃子的實(shí)例,用來(lái)放饅頭 
 class Basket{ 
   private int index = 0;// 表示裝到第幾個(gè)了饅頭 
   private ManTou[] manTous = new ManTou[6];// 可以放6個(gè)饅頭 
   // 放進(jìn)去一個(gè)饅頭 
   public synchronized void push(ManTou manTou) { 
     while(index==manTous.length){ 
       try { 
         System.out.println("籃子滿了!"); 
         this.wait(); 
       } catch (InterruptedException e) { 
         e.printStackTrace(); 
       } 
     } 
     System.out.println(Thread.currentThread().getName()+"生產(chǎn)"+manTou.toString()); 
     this.notify(); 
     manTous[index] = manTou; 
     index++; 
   } 
   // 拿一個(gè)饅頭 
   public synchronized ManTou pop() { 
     while (index==0) { 
       try { 
         System.out.println("籃子空了!"); 
         this.wait(); 
       } catch (InterruptedException e) { 
         e.printStackTrace(); 
       } 
     } 
     ManTou manTou=manTous[--index]; 
     System.out.println(Thread.currentThread().getName()+"吃了"+manTou.toString()); 
     this.notify(); 
     return manTou; 
   } 
 } 

生產(chǎn)者:

 // 生產(chǎn)者,生產(chǎn)饅頭 
 class Producer implements Runnable { 
   private BasketBall basketBall; 
   public Producer(BasketBall basketBall) { 
     this.basketBall = basketBall; 
   } 
   @Override 
   public void run() { 
     for (int i = 0; i < 20; i++) { 
       ManTou manTou = new ManTou(i);// 生產(chǎn)饅頭 
       basketBall.push(manTou); 
       try { 
         Thread.sleep(500); 
       } catch (InterruptedException e) { 
         e.printStackTrace(); 
       } 
     } 
   } 
 } 
 // 消費(fèi)者,拿饅頭吃 
 class Consumer implements Runnable { 
   private BasketBall basketBall; 
   public Consumer(BasketBall basketBall) { 
     this.basketBall = basketBall; 
   } 
   @Override 
   public void run() { 
     for (int i = 0; i < 20; i++) { 
       ManTou manTou=basketBall.pop(); 
       try { 
         Thread.sleep(1000); 
       } catch (InterruptedException e) { 
         e.printStackTrace(); 
       } 
     } 
   } 
 } 

測(cè)試:

 public class ProducerConsumer { 
   public static void main(String[] args) { 
     BasketBall basketBall=new BasketBall(); 
     new Thread(new Producer(basketBall)).start(); 
     new Thread(new Consumer(basketBall)).start(); 
   } 
 }

以上所述是小編給大家介紹的Java線程同步機(jī)制,希望對(duì)大家有所幫助,如果大家有任何疑問(wèn)請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!

相關(guān)文章

最新評(píng)論