电脑知识|欧美黑人一区二区三区|软件|欧美黑人一级爽快片淫片高清|系统|欧美黑人狂野猛交老妇|数据库|服务器|编程开发|网络运营|知识问答|技术教程文章 - 好吧啦网

您的位置:首頁(yè)技術(shù)文章
文章詳情頁(yè)

深入理解Java 線(xiàn)程通信

瀏覽:3日期:2022-08-30 16:27:47

當(dāng)線(xiàn)程在系統(tǒng)內(nèi)運(yùn)行時(shí),線(xiàn)程的調(diào)度具有一定的透明性,程序通常無(wú)法準(zhǔn)確控制線(xiàn)程的輪換執(zhí)行,但 Java 也提供了一些機(jī)制來(lái)保證線(xiàn)程協(xié)調(diào)運(yùn)行。

傳統(tǒng)的線(xiàn)程通信

假設(shè)現(xiàn)在系統(tǒng)中有兩個(gè)線(xiàn)程,這兩個(gè)線(xiàn)程分別代表存款者和取錢(qián)者——現(xiàn)在假設(shè)系統(tǒng)有一種特殊的要求,系統(tǒng)要求存款者和取錢(qián)者不斷地重復(fù)存款、取錢(qián)的動(dòng)作,而且要求每當(dāng)存款者將錢(qián)存入指定賬戶(hù)后,取錢(qián)者就立即取出該筆錢(qián)。不允許存款者連續(xù)兩次存錢(qián),也不允許取錢(qián)者連續(xù)兩次取錢(qián)。

為了實(shí)現(xiàn)這種功能,可以借助于 Object 類(lèi)提供的 wait()、 notify() 和 notifyAll() 三個(gè)方法,這三個(gè)方法并不屬于 Thread 類(lèi),而是屬于 Object 類(lèi)。但這三個(gè)方法必須由同步監(jiān)視器對(duì)象來(lái)調(diào)用,這可分成以下兩種情況。

對(duì)于使用 synchronized 修飾的同步方法,因?yàn)樵擃?lèi)的默認(rèn)實(shí)例(this)就是同步監(jiān)視器,所以可以在同步方法中直接調(diào)用這三個(gè)方法。 對(duì)于使用 synchronized 修飾的同步代碼塊,同步監(jiān)視器是 synchronized 后括號(hào)里的對(duì)象,所以必須使用該對(duì)象調(diào)用這三個(gè)方法。

關(guān)于這三個(gè)方法的解釋如下。

wait():導(dǎo)致當(dāng)前線(xiàn)程等待,直到其他線(xiàn)程調(diào)用該同步監(jiān)視器的 notify() 方法或 notifyAll() 方法來(lái)喚醒該線(xiàn)程。該 wait() 方法有三種形式——無(wú)時(shí)間參數(shù)的 wait (—直等待,直到其他線(xiàn)程通知 )、帶毫秒?yún)?shù)的 wait() 和帶毫秒、毫微秒?yún)?shù)的 wait() (這兩種方法都是等待指定時(shí)間后自動(dòng)蘇醒)。調(diào)用 wait() 方法的當(dāng)前線(xiàn)程會(huì)釋放對(duì)該同步監(jiān)視器的鎖定。 notify():?jiǎn)拘言诖送奖O(jiān)視器上等待的單個(gè)線(xiàn)程。如果所有線(xiàn)程都在此同步監(jiān)視器上等待,則會(huì)選擇喚醒其中一個(gè)線(xiàn)程。選擇是任意性的。只有當(dāng)前線(xiàn)程放棄對(duì)該同步監(jiān)視器的鎖定后(使用 wait() 方法),才可以執(zhí)行被喚醒的線(xiàn)程。 notifyAll():?jiǎn)拘言诖送奖O(jiān)視器上等待的所有線(xiàn)程。只有當(dāng)前線(xiàn)程放棄對(duì)該同步監(jiān)視器的鎖定后,才可以執(zhí)行被喚醒的線(xiàn)程。

程序中可以通過(guò)一個(gè)旗標(biāo)來(lái)標(biāo)識(shí)賬戶(hù)中是否已有存款,當(dāng)旗標(biāo)為 false 時(shí),表明賬戶(hù)中沒(méi)有存款,存款者線(xiàn)程可以向下執(zhí)行,當(dāng)存款者把錢(qián)存入賬戶(hù)后,將旗標(biāo)設(shè)為 true ,并調(diào)用 notify() 或 notifyAll() 方法來(lái)喚醒其他線(xiàn)程;當(dāng)存款者線(xiàn)程進(jìn)入線(xiàn)程體后,如果旗標(biāo)為 true 就調(diào)用 wait() 方法讓該線(xiàn)程等待。

當(dāng)旗標(biāo)為 true 時(shí),表明賬戶(hù)中已經(jīng)存入了存款,則取錢(qián)者線(xiàn)程可以向下執(zhí)行,當(dāng)取錢(qián)者把錢(qián)從賬戶(hù)中取出后,將旗標(biāo)設(shè)為 false ,并調(diào)用 notify() 或 notifyAll() 方法來(lái)喚醒其他線(xiàn)程;當(dāng)取錢(qián)者線(xiàn)程進(jìn)入線(xiàn)程體后,如果旗標(biāo)為 false 就調(diào)用 wait() 方法讓該線(xiàn)程等待。

本程序?yàn)?Account 類(lèi)提供 draw() 和 deposit() 兩個(gè)方法,分別對(duì)應(yīng)該賬戶(hù)的取錢(qián)、存款等操作,因?yàn)檫@兩個(gè)方法可能需要并發(fā)修改 Account 類(lèi)的 balance 成員變量的值,所以這兩個(gè)方法都使用 synchronized 修飾成同步方法。除此之外,這兩個(gè)方法還使用了 wait() 和 notifyAll() 來(lái)控制線(xiàn)程的協(xié)作。

public class Account{ private String accountNo; private double balance; //標(biāo)識(shí)賬戶(hù)中是否已有存款的旗標(biāo) private boolean flag = false; public Account(){} public Account(String accountNo , double balance){ this.accountNo = accountNo; this.balance = balance; } public void setAccountNo(String accountNo){ this.accountNo = accountNo; } public String getAccountNo(){ return this.accountNo; } public double getBalance(){ return this.balance; } public synchronized void draw(double drawAmount){ try{ //如果flag為假,表明賬戶(hù)中還沒(méi)有人存錢(qián)進(jìn)去,則取錢(qián)方法阻塞 if (!flag){wait(); }else{//執(zhí)行取錢(qián)System.out.println(Thread.currentThread().getName() + ' 取錢(qián):' + drawAmount);balance -= drawAmount;System.out.println('賬戶(hù)余額為:' + balance);//將標(biāo)識(shí)賬戶(hù)是否已有存款的旗標(biāo)設(shè)為false。flag = false;//喚醒其他線(xiàn)程notifyAll(); } }catch (InterruptedException ex){ ex.printStackTrace(); } } public synchronized void deposit(double depositAmount){ try{ //如果flag為真,表明賬戶(hù)中已有人存錢(qián)進(jìn)去,則存錢(qián)方法阻塞 if (flag){ // ①wait(); }else{//執(zhí)行存款System.out.println(Thread.currentThread().getName() + ' 存款:' + depositAmount);balance += depositAmount;System.out.println('賬戶(hù)余額為:' + balance);//將表示賬戶(hù)是否已有存款的旗標(biāo)設(shè)為trueflag = true;//喚醒其他線(xiàn)程notifyAll(); } }catch (InterruptedException ex){ ex.printStackTrace(); } } public int hashCode(){ return accountNo.hashCode(); } public boolean equals(Object obj){ if (obj != null && obj.getClass() == Account.class){ Account target = (Account)obj; return target.getAccountNo().equals(accountNo); } return false; }}

上面程序中的粗體字代碼使用 wait() 和 notifyAll() 進(jìn)行了控制,對(duì)存款者線(xiàn)程而言,當(dāng)程序進(jìn)入 deposit() 方法后,如果 flag 為 true ,則表明賬戶(hù)中已有存款,程序調(diào)用 wait() 方法阻塞;否則程序向下執(zhí)行存款操作,當(dāng)存款操作執(zhí)行完成后,系統(tǒng)將 flag 設(shè)為 true,然后調(diào)用 notifyAll() 來(lái)喚醒其他被阻塞的線(xiàn)程——如果系統(tǒng)中有存款者線(xiàn)程,存款者線(xiàn)程也會(huì)被喚醒,但該存款者線(xiàn)程執(zhí)行到①號(hào)代碼處時(shí)再次進(jìn)入阻塞狀態(tài),只有執(zhí)行 draw() 方法的取錢(qián)者線(xiàn)程才可以向下執(zhí)行。同理,取錢(qián)者線(xiàn)程的運(yùn)行流程也是如此。

程序中的存款者線(xiàn)程循環(huán)100次重復(fù)存款,而取錢(qián)者線(xiàn)程則循環(huán)100次重復(fù)取錢(qián),存款者線(xiàn)程和取錢(qián)者線(xiàn)程分別調(diào)用 Account 對(duì)象的 deposit()、 draw() 方法來(lái)實(shí)現(xiàn)。

public class DrawThread extends Thread{ //模擬用戶(hù)賬戶(hù) private Account account; //當(dāng)前取錢(qián)線(xiàn)程所希望取的錢(qián)數(shù) private double drawAmount; public DrawThread(String name, Account account, double drawAmount){ super(name); this.account = account; this.drawAmount = drawAmount; } //重復(fù)100次執(zhí)行取錢(qián)操作 public void run(){ for (int i = 0 ; i < 100 ; i++ ){ account.draw(drawAmount); } }}

public class DepositThread extends Thread{ //模擬用戶(hù)賬戶(hù) private Account account; //當(dāng)前取錢(qián)線(xiàn)程所希望存款的錢(qián)數(shù) private double depositAmount; public DepositThread(String name, Account account, double depositAmount){ super(name); this.account = account; this.depositAmount = depositAmount; } //重復(fù)100次執(zhí)行存款操作 public void run(){ for (int i = 0 ; i < 100 ; i++ ){ account.deposit(depositAmount); } }}

主程序可以啟動(dòng)任意多個(gè)存款線(xiàn)程和取錢(qián)線(xiàn)程,可以看到所有的取錢(qián)線(xiàn)程必須等存款線(xiàn)程存錢(qián)后才可以向下執(zhí)行,而存款線(xiàn)程也必須等取錢(qián)線(xiàn)程取錢(qián)后才可以向下執(zhí)行。主程序代碼如下。

public class TestDraw{ public static void main(String[] args){ //創(chuàng)建一個(gè)賬戶(hù) Account acct = new Account('1234567' , 0); new DrawThread('取錢(qián)者' , acct , 800).start(); new DepositThread('存款者甲' , acct , 800).start(); new DepositThread('存款者乙' , acct , 800).start(); new DepositThread('存款者丙' , acct , 800).start(); }}

運(yùn)行該程序,可以看到存款者線(xiàn)程、取錢(qián)者線(xiàn)程交替執(zhí)行的情形,每當(dāng)存款者向賬戶(hù)中存入800元之后,取錢(qián)者線(xiàn)程立即從賬戶(hù)中取出這筆錢(qián)。存款完成后賬戶(hù)余額總是800元,取錢(qián)結(jié)束后賬戶(hù)余額總是0元。運(yùn)行該程序,會(huì)看到如下圖所示的結(jié)果。

深入理解Java 線(xiàn)程通信

從上圖中可以看出 , 3個(gè)存款者線(xiàn)程隨機(jī)地向賬戶(hù)中存款,只有1個(gè)取錢(qián)者線(xiàn)程執(zhí)行取錢(qián)操作。只有當(dāng)取錢(qián)者取錢(qián)后,存款者才可以存款;同理,只有等存款者存款后,取錢(qián)者線(xiàn)程才可以取錢(qián)。

上圖顯示程序最后被阻塞無(wú)法繼續(xù)向下執(zhí)行,這因?yàn)?個(gè)存款者線(xiàn)程共有300次存款操作,但1個(gè)取錢(qián)者線(xiàn)程只有100次取錢(qián)操作,所以程序最后被阻塞。

注意:上圖所示的阻塞并不是死鎖,對(duì)于這種情況,取錢(qián)者線(xiàn)程已經(jīng)執(zhí)行結(jié)束,而存款者線(xiàn)程只是在等待其他線(xiàn)程來(lái)取錢(qián)而已,并不是等待其他線(xiàn)程釋放同步監(jiān)視器。不要把死鎖和程序阻塞等同起來(lái)!

使用 Condition 控制線(xiàn)程通信

如果程序不使用 synchronized 關(guān)鍵字來(lái)保證同步,而是直接使用 Lock 對(duì)象來(lái)保證同步,則系統(tǒng)中不存在隱式的同步監(jiān)視器,也就不能使用 wait()、notify()、notifyAll() 方法進(jìn)行線(xiàn)程通信了。

當(dāng)使用 Lock 對(duì)象來(lái)保證同步時(shí),Java 提供了一個(gè) Condition 類(lèi)來(lái)保持協(xié)調(diào),使用 Condition 可以讓那些已經(jīng)得到 Lock 對(duì)象卻無(wú)法繼續(xù)執(zhí)行的線(xiàn)程釋放 Lock 對(duì)象,Condition 對(duì)象也可以喚醒其他處于等待的線(xiàn)程。

Condition 將同步監(jiān)視器方法(wait()、notify() 和 notifyAll() )分解成截然不同的對(duì)象,以便通過(guò)將這些對(duì)象與 Lock 對(duì)象組合使用,為每個(gè)對(duì)象提供多個(gè)等待集(wait-set)。在這種情況下,Lock 替代了同步方法或同步代碼塊,Condition 替代了同步監(jiān)視器的功能。

Condition 實(shí)例被綁定在一個(gè) Lock 對(duì)象上。要獲得特定 Lock 實(shí)例的 Condition 實(shí)例,調(diào)用 Lock 對(duì)象的 newCondition() 方法即可。Condition 類(lèi)提供了如下三個(gè)方法。

await():類(lèi)似于隱式同步監(jiān)視器上的 wait() 方法,導(dǎo)致當(dāng)前線(xiàn)程等待,直到其他線(xiàn)程調(diào)用該 Condition 的 signal() 方法或 signalAll() 方法來(lái)喚醒該線(xiàn)程。該 await() 方法有更多變體,如 long awaitNanos(long nanosTimeout)、 void awaitUninterruptibly() 、 awaitUntil(Date deadline) 等,可以完成更豐富的等待操作。 signal():?jiǎn)拘言诖?Lock 對(duì)象上等待的單個(gè)線(xiàn)程。如果所有線(xiàn)程都在該 Lock 對(duì)象上等待,則會(huì)選擇喚醒其中一個(gè)線(xiàn)程。選擇是任意性的。只有當(dāng)前線(xiàn)程放棄對(duì)該 Lock 對(duì)象的鎖定后(使用 await() 方法),才可以執(zhí)行被喚醒的線(xiàn)程。 signalAll():?jiǎn)拘言诖?Lock 對(duì)象上等待的所有線(xiàn)程。只有當(dāng)前線(xiàn)程放棄對(duì)該 Lock 對(duì)象的鎖定后,才可以執(zhí)行被喚醒的線(xiàn)程。

下面程序中 Account 使用 Lock 對(duì)象來(lái)控制同步,并使用 Condition 對(duì)象來(lái)控制線(xiàn)程的協(xié)調(diào)運(yùn)行。

public class Account{ //顯示定義Lock對(duì)象 private final Lock lock = new ReentrantLock(); //獲得指定Lock對(duì)象對(duì)應(yīng)的條件變量 private final Condition cond = lock.newCondition(); private String accountNo; private double balance; //標(biāo)識(shí)賬戶(hù)中是否已經(jīng)存款的旗標(biāo) private boolean flag = false; public Account(){} public Account(String accountNo , double balance){ this.accountNo = accountNo; this.balance = balance; } public void setAccountNo(String accountNo){ this.accountNo = accountNo; } public String getAccountNo(){ return this.accountNo; } public double getBalance(){ return this.balance; } public void draw(double drawAmount){ //加鎖 lock.lock(); try{ //如果賬戶(hù)中還沒(méi)有存入存款,該線(xiàn)程等待 if (!flag){cond.await(); }else{//執(zhí)行取錢(qián)操作System.out.println(Thread.currentThread().getName() + ' 取錢(qián):' + drawAmount);balance -= drawAmount;System.out.println('賬戶(hù)余額為:' + balance);//將標(biāo)識(shí)是否成功存入存款的旗標(biāo)設(shè)為falseflag = false;//喚醒該Lock對(duì)象對(duì)應(yīng)的其他線(xiàn)程cond.signalAll(); } }catch (InterruptedException ex){ ex.printStackTrace(); } //使用finally塊來(lái)確保釋放鎖 finally{ lock.unlock(); } } public void deposit(double depositAmount){ lock.lock(); try{ //如果賬戶(hù)中已經(jīng)存入了存款,該線(xiàn)程等待 if(flag){cond.await(); }else{//執(zhí)行存款操作System.out.println(Thread.currentThread().getName() + ' 存款:' + depositAmount);balance += depositAmount;System.out.println('賬戶(hù)余額為:' + balance);//將標(biāo)識(shí)是否成功存入存款的旗標(biāo)設(shè)為trueflag = true;//喚醒該Lock對(duì)象對(duì)應(yīng)的其他線(xiàn)程cond.signalAll(); } }catch (InterruptedException ex){ ex.printStackTrace(); } //使用finally塊來(lái)確保釋放鎖 finally{ lock.unlock(); } } public int hashCode(){ return accountNo.hashCode(); } public boolean equals(Object obj){ if (obj != null && obj.getClass() == Account.class){ Account target = (Account)obj; return target.getAccountNo().equals(accountNo); } return false; }}

顯式地使用 Lock 對(duì)象來(lái)充當(dāng)同步監(jiān)視器,則需要使用 Condition 對(duì)象來(lái)暫停、喚醒指定線(xiàn)程。存取錢(qián)的代碼和最上面相同。

使用阻塞隊(duì)列(BlockingQueue)控制線(xiàn)程通信

Java5 提供了一個(gè) BlockingQueue 接口,雖然 BlockingQueue 也是 Queue 的子接口,但它的主要用途并不是作為容器,而是作為線(xiàn)程同步的工具。 BlockingQueue 具有一個(gè)特征:當(dāng)生產(chǎn)者線(xiàn)程試圖向 BlockingQueue 中放入元素時(shí),如果該隊(duì)列已滿(mǎn),則該線(xiàn)程被阻塞;當(dāng)消費(fèi)者線(xiàn)程試圖從 BlockingQueue 中取出元素時(shí),如果該隊(duì)列已空,則該線(xiàn)程被阻塞。

程序的兩個(gè)線(xiàn)程通過(guò)交替向 BlockingQueue 中放入元素、取出元素,即可很好地控制線(xiàn)程的通信。BlockingQueue 提供如下兩個(gè)支持阻塞的方法。

put(E e):嘗試把 E 元素放入 BlockingQueue 中,如果該隊(duì)列的元素己滿(mǎn),則阻塞該線(xiàn)程。 take():嘗試從 BlockingQueue 的頭部取出元素,如果該隊(duì)列的元素已空,則阻塞該線(xiàn)程。

BlockingQueue 繼承了 Queue 接口,當(dāng)然也可使用 Queue 接口中的方法。這些方法歸納起來(lái)可分為如下三組。

在隊(duì)列尾部插入元素。包括 add(E e)、offer(E e) 和 put(E e) 方法,當(dāng)該隊(duì)列已滿(mǎn)時(shí),這三個(gè)方法分別會(huì)拋出異常、返回 false 、阻塞隊(duì)列。 在隊(duì)列頭部刪除并返回刪除的元素。包括 remove()、 poll() 和 take() 方法。當(dāng)該隊(duì)列已空時(shí),這三個(gè)方法分別會(huì)拋出異常、返回 false 、阻塞隊(duì)列。 在隊(duì)列頭部取出但不刪除元素。包括 element() 和 peek() 方法,當(dāng)隊(duì)列已空時(shí),這兩個(gè)方法分別拋出異常、返回 false

BlockingQueue 包含的方法之間的對(duì)應(yīng)關(guān)系如下表所示:

深入理解Java 線(xiàn)程通信

BlockingQueue 與其實(shí)現(xiàn)類(lèi)之間的類(lèi)圖如下圖所示。

深入理解Java 線(xiàn)程通信

上圖中以黑色方框框出的都是 Java7 新增的阻塞隊(duì)列??梢钥吹?, BlockingQueue 包含如下5個(gè)實(shí)現(xiàn)類(lèi)。

ArrayBlockingQueue:基于數(shù)組實(shí)現(xiàn)的 BlockingQueue 隊(duì)列。 LinkedBlockingQueue:基于鏈表實(shí)現(xiàn)的 BlockingQueue 隊(duì)列。 PriorityBlockingQueue:它并不是標(biāo)準(zhǔn)的阻塞隊(duì)列。與前面介紹的 PriorityQueue 類(lèi)似,該隊(duì)列調(diào)用 remove()、poll()、take() 等方法取出元素時(shí),并不是取出隊(duì)列中存在時(shí)間最長(zhǎng)的元素,而是隊(duì)列中最小的元素。 PriorityBlockingQueue 判斷元素的大小即可根據(jù)元素(實(shí)現(xiàn) Comparable 接口)的本身大小來(lái)自然排序,也可使用 Comparator 進(jìn)行定制排序。 SynchronousQueue:同步隊(duì)列。對(duì)該隊(duì)列的存、取操作必須交替進(jìn)行。 DelayQueue:它是一個(gè)特殊的 BlockingQueue ,底層基于 PriorityBlockingQueue 實(shí)現(xiàn)。不過(guò),DelayQueue 要求集合元素都實(shí)現(xiàn) Delay 接口(該接口里只有一個(gè) long getDelay() 方法),DelayQueue 根據(jù)集合元素的 getDalay() 方法的返回值進(jìn)行排序。

下面以 ArrayBlockingQueue 為例介紹阻塞隊(duì)列的功能和用法。下面先用一個(gè)最簡(jiǎn)單的程序來(lái)測(cè)試 BlockingQueue 的 put() 方法。

public class BlockingQueueTest { public static void main(String[] args) throws Exception { BlockingQueue<String> bq = new ArrayBlockingQueue<>(2); bq.put('Java'); // 與bq.add('Java')、bq.offer('Java') 相同 bq.put('Java'); // 與bq.add('Java')、bq.offer('Java') 相同 bq.put('Java'); // ① 阻塞線(xiàn)程 }}

上面程序先定義一個(gè)大小為2的 BlockingQueue,程序先向該隊(duì)列中放入兩個(gè)元素,此時(shí)隊(duì)列還沒(méi)有滿(mǎn),兩個(gè)元紊都可以放入,因此使用 put()、add() 和 offer() 方法效果完全一樣。當(dāng)程序試圖放入第三個(gè)元素時(shí),如果使用 put() 方法嘗試放入元素將會(huì)阻寒線(xiàn)程,如上面程序①號(hào)代碼所示。如果使用 add() 方法嘗試放入元素將會(huì)引發(fā)異常;如果使用 offer() 方法嘗試放入元素則會(huì)返回 false,元素不會(huì)被放入。

與此類(lèi)似的是,在 BlockingQueue 已空的情況下,程序使用 take() 方法嘗試取出元素將會(huì)阻塞線(xiàn)程:使用 remove() 方法嘗試取出元素將引發(fā)異常:使用 poll() 方法嘗試取出元素將返回 false,元索不會(huì)被刪除。

掌握了 BlodcingQuene 阻塞隊(duì)列的特性之后,下面程序就可以利用 BlockingQueue 來(lái)實(shí)現(xiàn)線(xiàn)程通信了。

public class Producer extends Thread { private BlockingQueue<String> bq; public Producer(BlockingQueue<String> bq) { this.bq = bq; } public void run() { String[] strArr = new String[] {'Java','Struts','Spring' };for(int i=0;i<99999999;i++) { System.out.println(getName()+'生產(chǎn)者準(zhǔn)備生產(chǎn)集合元素'); try {Thread.sleep(200);// 嘗試放入元素,如果隊(duì)列已滿(mǎn),則線(xiàn)程被阻塞bq.put(strArr[i%3]); }catch(Exception ex) {ex.printStackTrace(); } System.out.println(getName()+'生產(chǎn)完成:'+bq); } }}public class Consumer extends Thread { private BlockingQueue<String> bq; public Consumer(BlockingQueue<String> bq) { this.bq = bq; } public void run() { while(true) { System.out.println(getName()+'消費(fèi)者準(zhǔn)備消費(fèi)集合元素!'); try {Thread.sleep(200);// 嘗試取出元素,如果隊(duì)列已空,則線(xiàn)程被阻塞bq.take(); }catch(Exception ex) {ex.printStackTrace(); } System.out.println(getName()+'消費(fèi)完成:'+bq); } }}public class BlockingQueueTest2 { public static void main(String[] args) { // 創(chuàng)建一個(gè)容量為1的BlockingQueue BlockingQueue<String> bq = new ArrayBlockingQueue<>(1); // 啟動(dòng)3個(gè)生產(chǎn)者線(xiàn)程 new Producer(bq).start(); new Producer(bq).start(); new Producer(bq).start(); // 啟動(dòng)一個(gè)消費(fèi)者線(xiàn)程 new Consumer(bq).start(); }}

上面程序啟動(dòng)了 3個(gè)生產(chǎn)者線(xiàn)程向 BlockingQueue 集合放入元素,啟動(dòng)了 1個(gè)消費(fèi)者線(xiàn)程從 BlockingQueue 集合取出元素。本程序的 BlockingQueue 集合容量為1,因此3個(gè)生產(chǎn)者線(xiàn)程無(wú)法連續(xù)放入元素,必須等待消費(fèi)者線(xiàn)程取出一個(gè)元素后 , 3個(gè)生產(chǎn)者線(xiàn)程的其中之一才能放入一個(gè)元素。運(yùn)行該程序,會(huì)看到如下圖所示的結(jié)果。

深入理解Java 線(xiàn)程通信

從上圖可以看出,3個(gè)生產(chǎn)者線(xiàn)程都想向 BlockingQueue 中放入元素,但只要其中一個(gè)線(xiàn)程向該隊(duì)列中放入元素之后,其他生產(chǎn)者線(xiàn)程就必須等待,等待消費(fèi)者線(xiàn)程取出 BlockingQueue 隊(duì)列里的元素。

以上就是深入理解Java 線(xiàn)程通信的詳細(xì)內(nèi)容,更多關(guān)于Java 線(xiàn)程通信的資料請(qǐng)關(guān)注好吧啦網(wǎng)其它相關(guān)文章!

標(biāo)簽: Java
相關(guān)文章:
主站蜘蛛池模板: 政府园区专业委托招商平台_助力企业选址项目快速落地_东方龙商务集团 | 三佳互联一站式网站建设服务|网站开发|网站设计|网站搭建服务商 赛默飞Thermo veritiproPCR仪|ProFlex3 x 32PCR系统|Countess3细胞计数仪|371|3111二氧化碳培养箱|Mirco17R|Mirco21R离心机|仟诺生物 | 山东led显示屏,山东led全彩显示屏,山东LED小间距屏,临沂全彩电子屏-山东亚泰视讯传媒有限公司 | 牛皮纸|牛卡纸|进口牛皮纸|食品级牛皮纸|牛皮纸厂家-伽立实业 | 佛山市钱丰金属不锈钢蜂窝板定制厂家|不锈钢装饰线条|不锈钢屏风| 电梯装饰板|不锈钢蜂窝板不锈钢工艺板材厂家佛山市钱丰金属制品有限公司 | 石英砂矿石色选机_履带辣椒色选机_X光异物检测机-合肥幼狮光电科技 | 欧美日韩国产一区二区三区不_久久久久国产精品无码不卡_亚洲欧洲美洲无码精品AV_精品一区美女视频_日韩黄色性爱一级视频_日本五十路人妻斩_国产99视频免费精品是看4_亚洲中文字幕无码一二三四区_国产小萍萍挤奶喷奶水_亚洲另类精品无码在线一区 | 塑木弯曲试验机_铜带拉伸强度试验机_拉压力测试台-倾技百科 | 沥青灌缝机_路面灌缝机_道路灌缝机_沥青灌缝机厂家_济宁萨奥机械有限公司 | 中空玻璃生产线,玻璃加工设备,全自动封胶线,铝条折弯机,双组份打胶机,丁基胶/卧式/立式全自动涂布机,玻璃设备-山东昌盛数控设备有限公司 | 众能联合-提供高空车_升降机_吊车_挖机等一站工程设备租赁 | 大型冰雕-景区冰雕展制作公司,3D创意设计源头厂家-[赛北冰雕] | 办公室家具_板式办公家具定制厂家-FMARTS福玛仕办公家具 | 对照品_中药对照品_标准品_对照药材_「格利普」高纯中药标准品厂家-成都格利普生物科技有限公司 澳门精准正版免费大全,2025新澳门全年免费,新澳天天开奖免费资料大全最新,新澳2025今晚开奖资料,新澳马今天最快最新图库 | 沈阳楼承板_彩钢板_压型钢板厂家-辽宁中盛绿建钢品股份有限公司 轴承振动测量仪电箱-轴承测振动仪器-测试仪厂家-杭州居易电气 | 注浆压力变送器-高温熔体传感器-矿用压力传感器|ZHYQ朝辉 | 硅PU球场、篮球场地面施工「水性、环保、弹性」硅PU材料生产厂家-广东中星体育公司 | 注塑_注塑加工_注塑模具_塑胶模具_注塑加工厂家_深圳环科 | 道达尔润滑油-食品级润滑油-道达尔导热油-合成导热油,深圳道达尔代理商合-深圳浩方正大官网 | 断桥铝破碎机_铝合金破碎机_废铁金属破碎机-河南鑫世昌机械制造有限公司 | 章丘丰源机械有限公司 - 三叶罗茨风机,罗茨鼓风机,罗茨风机 | 化工ERP软件_化工新材料ERP系统_化工新材料MES软件_MES系统-广东顺景软件科技有限公司 | 【直乐】河北石家庄脊柱侧弯医院_治疗椎间盘突出哪家医院好_骨科脊柱外科专业医院_治疗抽动症/关节病骨伤权威医院|排行-直乐矫形中医医院 | 赛默飞Thermo veritiproPCR仪|ProFlex3 x 32PCR系统|Countess3细胞计数仪|371|3111二氧化碳培养箱|Mirco17R|Mirco21R离心机|仟诺生物 | 合肥网带炉_安徽箱式炉_钟罩炉-合肥品炙装备科技有限公司 | 软文推广发布平台_新闻稿件自助发布_媒体邀约-澜媒宝 | LZ-373测厚仪-华瑞VOC气体检测仪-个人有毒气体检测仪-厂家-深圳市深博瑞仪器仪表有限公司 | 自动售货机_无人售货机_专业的自动售货机运营商_免费投放售货机-广州富宏主官网 | 耳模扫描仪-定制耳机设计软件-DLP打印机-asiga打印机-fitshape「飞特西普」 | 北京中航时代-耐电压击穿试验仪厂家-电压击穿试验机 | 粉末冶金-粉末冶金齿轮-粉末冶金零件厂家-东莞市正朗精密金属零件有限公司 | 长沙中央空调维修,中央空调清洗维保,空气能热水工程,价格,公司就找维小保-湖南维小保环保科技有限公司 | 网带通过式抛丸机,,网带式打砂机,吊钩式,抛丸机,中山抛丸机生产厂家,江门抛丸机,佛山吊钩式,东莞抛丸机,中山市泰达自动化设备有限公司 | CCC验厂-家用电器|服务器CCC认证咨询-奥测世纪 | 智慧农业|农业物联网|现代农业物联网-托普云农物联网官方网站 | 广东佛电电器有限公司|防雷开关|故障电弧断路器|智能量测断路器 广东西屋电气有限公司-广东西屋电气有限公司 | 细砂提取机,隔膜板框泥浆污泥压滤机,螺旋洗砂机设备,轮式洗砂机械,机制砂,圆锥颚式反击式破碎机,振动筛,滚筒筛,喂料机- 上海重睿环保设备有限公司 | 根系分析仪,大米外观品质检测仪,考种仪,藻类鉴定计数仪,叶面积仪,菌落计数仪,抑菌圈测量仪,抗生素效价测定仪,植物表型仪,冠层分析仪-杭州万深检测仪器网 | 闪电优家-卫生间防水补漏_酒店漏水渗水维修_防水堵漏公司 | 注塑机-压铸机-塑料注塑机-卧式注塑机-高速注塑机-单缸注塑机厂家-广东联升精密智能装备科技有限公司 | 深圳活动策划公司|庆典策划|专业公关活动策划|深圳艺典文化传媒 重庆中专|职高|技校招生-重庆中专招生网 |