Java开发笔记(一百零三)线程间的通信方式
前面介紹了多線程并發之時的資源搶占情況,以及利用同步、加鎖、信號量等機制解決資源沖突問題,不過這些機制只適合同一資源的共享分配,并未涉及到某件事由的前因后果。日常生活中,經常存在兩個前后關聯的事務,像雇員和雇主這兩個角色,他們之間的某些工作就帶有因果關系。比如要等雇主接到了項目,雇員才有活干;又如每月末員工都等著老板發工資,這樣才有錢逛街和吃大餐,此時員工的消費行為便依賴于老板的發薪水動作。如此看來,兩個線程之間理應建立某種消息通路,每當線程A完成某個事項,就將完成標志通知線程B,線程B收到通知之后,認為前提條件已經滿足,這才進行后續的處理過程。線程之間的消息通路,可視作在線程間傳遞信息,專業的說法叫做“通信”,如何在多線程并發時進行有效通信,這是多線程技術中的一大課題。
依據線程并發時的不同管理機制,線程間的通信也各有不同的方式,接下來將分別論述同步機制與加鎖機制之下的兩種線程通信過程。
首先是同步機制,采用同步代碼塊的話,需要在關鍵字synchronized后面補充待同步的對象實例,之前的同步代碼塊統一寫成“synchronized (this)”。可是圓括號內部一定要填this嗎?圓括號的內部參數究竟是干什么用的?其實synchronized附帶的圓括號參數正是在線程間通信的郵差,以前的同步演示代碼由于沒進行線程通信,因此圓括號里的參數沒有具體要求,一般填this即可。現在要想在線程間進行通信,就必須啟用圓括號參數了,并且兩個線程都要在synchronized后面填寫該參數對象。
舉個例子,雇員等著雇主發工資,那員工怎樣才知道老板已經發了呢?要是由員工自己一會兒一會兒去查銀行卡,平時的工作都會受到影響,所以可讓員工留個等工資的心眼就好。然后老板一個一個發工資,發完之后給員工遞個工資條,或者給員工發封工資郵件,這樣員工收到工資條便知薪水到賬了。那么在等工資和發工資這兩個線程之間,即可令工資條作為二者的信使,于是同步代碼塊可改寫為“synchronized (工資條對象)”的形式。同時工資條對象還要支持等待與發放兩個動作,因為這類動作早就隱藏在Object類的基本方法中,所以開發者不必擔心工資條對象該為Integer類型還是別的什么類型,凡是正常的實例都擁有等待與發放的方法,具體的方法說明如下:
wait:等待通知。
notify:在等待隊列中隨機挑選一個線程發放通知。
notifyAll:向等待隊列中的所有線程發放通知。
在編碼實現同步機制的通信過程時,先分別創建雇員和雇主的工作任務,其中雇員任務在同步代碼塊中調用工資條對象的wait方法,表示等著發工資;而雇主任務在同步代碼塊中調用工資條對象的notify方法,表示發完工資了。然后依次啟動員工線程和老板線程,員工線程負責等工資以及收到工資后的消費行為,老板線程負責發工資以及記賬操作。據此編寫的同步線程通信代碼示例如下:
運行上面的線程通信代碼,打印出以下的線程日志:
14:37:29.685 同步機制的員工 等著發工資。 14:37:29.994 同步機制的老板 開始發工資。 14:37:30.120 同步機制的老板 發完工資了。 14:37:30.120 同步機制的員工 今晚趕緊吃大餐。?
從日志可見,員工線程果然在等到工資之后才去吃大餐。
同步機制能夠通過wait/notify完成線程通信功能,那么加鎖機制又該如何進行線程間通信呢?既然加鎖機制設計了專門的鎖工具,那么鎖鑰內外的線程也只能通過鎖工具來通信,信使則為調用鎖對象的newCondition方法返回的Condition條件對象。條件對象同樣擁有等待與發放的方法,且與Object類的三個方法一一對應,具體說明如下:
await:等待通知。
signal:在等待隊列中隨機挑選一個線程發放通知。
signalAll:向等待隊列中的所有線程發放通知。
以可重入鎖ReentrantLock為例,依然要先分別創建雇員和雇主的工作任務,其中雇員任務在加鎖之后再調用條件對象的await方法,表示等著發工資;而雇主任務在加鎖之后再調用條件對象的signal方法,表示發完工資了;另外雇員任務和雇主任務均需在結束之前進行解鎖。然后依次啟動員工線程和老板線程,員工線程負責等工資以及收到工資后的消費行為,老板線程負責發工資以及記賬操作。下面是在加解鎖線程之間進行通信的代碼例子:
?
運行上述的線程通信代碼,打印出如下的線程日志:
14:57:07.794 加鎖機制的員工 等著發工資。 14:57:07.801 加鎖機制的老板 開始發工資。 14:57:07.905 加鎖機制的老板 發完工資了。 14:57:07.906 加鎖機制的員工 今晚趕緊吃大餐。?
可見加鎖機制同樣實現了線程間通信的功能。
更多Java技術文章參見《Java開發筆記(序)章節目錄》
轉載于:https://www.cnblogs.com/pinlantu/p/10933647.html
總結
以上是生活随笔為你收集整理的Java开发笔记(一百零三)线程间的通信方式的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C++ Qt 访问权限总结
- 下一篇: web服务器的简单实现——HTTP权威指