解析JVM线程同步机制
http://blog.csdn.net/thl789/article/details/566494
對多線程的支持一般是在OS級的,而Java將其做在了語言級別,這其中最吸引人的莫過于Java對線程同步(互斥與協作)的支持。本文分析了JVM(Java Virtual Machine)內部實現的監視器同步機制,并結合經典的生產者消費者同步問題,闡述Java語言級別上對此機制的支持。
關鍵詞:同步,互斥,協作,監視器,鎖
Keyword: Synchronization, Mutual Exclusion (Mutex), Cooperation, Monitor, Lock
?
目 ?錄
摘要... 1
目? 錄... 1
知識準備... 2
一、線程同步:互斥和協作... 2
二、解決同步的方案... 2
三、線程同步模型——監視器(Monitor)機制... 3
? 3.1 監視器模型... 3
? 3.2 監視器實現互斥... 4
? 3.3 監視器實現協作... 5
四、JVM線程同步的實現... 6
? 4.1 JVM線程模型... 6
? 4.2 對象鎖... 6
? 4.3 Java語言對線程同步的支持... 7
??? 4.3.1 同步方法與同步語句... 7
??? 4.3.2 協作——wait & notify/notifyAll7
五、利用JVM線程同步解決生產者消費者問題... 8
? 5.1 生產者消費者問題相關類層次... 8
? 5.2 生產者線程——threadSynch.ProducerConsumer.Producer9
? 5.3 消費者線程——threadSynch.ProducerConsumer.Consumer10
? 5.4 主程序——threadSynch.ProducerConsumer. ProducerConsumer11
? 5.5 程序運行時的一個快照... 11
六、總結... 12
參考資料及進一步閱讀... 13
關于作者... 13
?
知識準備
閱讀本文前,你應該具有操作系統的基本知識,知道Java的基本運行模式,最好還有過多線程的編程經驗。這些知識準備,可以閱讀本文后面所附的參考資料。
一、線程同步:互斥和協作
早期,順序程序設計(Sequential Programming)的模式一般是串行的執行“輸入——處理——輸出”,執行過程中可能還有用戶的交互或者執行其它I/O操作,而這一切直到最后的輸出,系統最珍貴的CPU資源都由這個程序對應的進程(Process)占有。為了提高CPU的利用率和任務的并行化,引入了并發程序設計(Concurrent Programming),也就相應的在OS內部有了并發進程的概念。在支持線程(Thread)的系統中,進程的實現和思考方法也適用,只是在OS調度的最小單元和資源的分配單元上有所區別。但是也要看對線程的支持實現在哪一級上,所以也就有了三種線程實現方式:內核級線程、用戶級線程和混和式線程。(關于這方面的知識,可閱讀參考文獻中的1或2)
支持多線程的系統中,并發線程在運行過程時,會有同步(Synchronization)的需求,同步包括了互斥(Mutual Exclusion,簡記為Mutex)與協作(Cooperation)兩個方面。多個線程交叉訪問臨界資源的時候,如果不把臨界區進行互斥管理,執行的結果可能就不是你預想的(這種沒有對臨界資源進行互斥訪問而出現的情況,你幾乎可以在任何講述并發編程的書中找到例子,這里不再贅述),這就需要將多個線程對臨界區的執行串行化。兩個或多個線程運行中,可能要協作完成一整件事,但是它們是相對獨立運行的,相互之間并不影響,所以需要某種機制使某個線程知道它下一步執行所依賴的條件是不是滿足,而這個條件是否滿足是要看另外一個線程的執行情況的,也就是通過某種協作機制使線程在單獨執行并行化的基礎上,實現多個線程的協作串行執行。
二、解決同步的方案
解決線程同步問題,早期的科學家提出了一些對于臨界區管理的方法,后來在操作系統中實現了信號量機制來解決經典的同步問題,在IEEE的POSIX(Portable Operating Systems Interface)標準中就進一步把線程進行了標準化,簡稱pThread標準,這其中也標準化了線程同步機制——互斥量等,目前很多類UNIX(UNIX-like)操作系統都已經實現了pThread。
實現臨界區的管理可以采用軟件方法,也可以用硬件方法。T.Dekker和G.L.Perterson分別提出了Dekker算法和Perterson算法,用軟件方法實現了對臨界區管理。硬件方法可以采用關中斷來解決,但是這種方式使系統效率大大的降低,甚至如果關中斷處理不當,還會使系統無法正常調度,而且也不適用于多處理器情況。現在幾乎所有的操作系統都實現了信號量(Semaphore)機制。信號量(Semaphore)通過一個記錄當前使用情況的標記value,等待該信號量的線程隊列queue和相應的PV操作原語實現同步。P操作相當于線程要使用該信號量所標志的資源,通過P操作來獲得,如果當前不可用,該線程就要被掛起;V操作相當于線程使用完該信號量所標志的資源,通過該操作來釋放它,如果有線程在等待這個資源并且資源當前可用,就采取某種策略選擇一個等待的線程,讓它擁有該資源,并繼續執行。根據value的初始值,信號量可以用來實現線程的互斥與協作。POSIX pThread的互斥量(Mutex)其實是信號量的一種特殊形式,但是使用互斥量要比用通用的信號量的同步機制來得容易。
Java利用JVM對線程執行期的完全控制,實現了監視器(Monitor)機制的線程同步,下面章節先介紹監視器機制,然后分析監視器機制在JVM中的實現。
三、線程同步模型——監視器(Monitor)機制
監視器支持上文所述的兩種線程同步:互斥與協作,而JVM通過對象鎖實現了監視器機制。本節就來闡述監視器模型,并分析它如何實現線程的互斥與協作。
3.1 監視器模型
?
?
圖一、監視器模型
?
圖一是監視器模型,監視器包括了三個部分,入口區、擁有區和等待區,入口區和等待區內可能有多個線程,但是任何時刻最多只有一個線程擁有該監視器。
線程對監視器的操作原語如下:
-“進入”監視器指線程進入入口區,準備獲取監視器,此時如果沒有別的線程擁有該監視器,則這個線程擁有此監視器,否則它要在入口區等待;
-“獲取”監視器指在入口區和等待區的線程按照某種策略機制被選擇可擁有該監視器時的操作;
-“擁有”監視器的線程在它擁有該監視器的時候排他地占有它,從而阻止其它線程的進入;
-“釋放”監視器 擁有監視器的線程執行完監視器范圍內的代碼或異常退出之后,要釋放掉它所擁有的此監視器。
監視器實現的是對臨界區的管理,對臨界區調度原則有16字要求——無空等待,有空讓進,擇一而入,算法可行。展開來說就是:
- 一次至多一個線程能夠在臨界區內;
- 不能讓一個線程無限地留在臨界區;
- 不能強迫一個線程無限地等待進入臨界區;
- 不能因所選的調度策略而造成線程的饑餓(Starving),甚至死鎖(Dead Lock)。
下面以經典的“生產者-消費者問題”為例,來分析利用監視器如何實現生產者進程與消費者進程之間的互斥與協作。簡化后的該問題的描述如下:生產者進程和消費者進程都對同一個緩沖區操作,生產者生產產品放到緩沖區,消費者消費緩沖區內的產品;如果緩沖區非空,則消費者讀取緩沖區的產品,消費掉產品的同時將緩沖區清空,否則消費者等待;如果緩沖區為空,則生產者生產產品放到緩沖區,否則生產者等待。
3.2 監視器實現互斥
利用監視器實現進程之間的互斥理解起來非常簡單。生產者消費者問題中的緩沖區是臨界資源,需要互斥訪問,可以用一個監視器來保護。生產者或消費者要訪問該共享的緩沖區首先必須擁有這個監視器,在監視器被別的線程占有時,該訪問線程必須在入口區或等待區等待。生產者和消費者對緩沖區的互斥訪問關系如圖二所示。
?
?
圖二、生產者-消費者之間的互斥
?
生產者與消費者各自獨立地執行,只有當它們需要訪問緩沖區(存放生產的產品或消費產品)的時候,才需要獲得與該緩沖區關聯的監視器,如果當前該監視器不能獲得,它們就在監視器的入口區等待。它們在離開臨界區的時候,釋放監視器,以允許其它競爭該監視器的線程進入。如果一個線程已經獲得了監視器,但是緩沖區的內容卻還不滿足自己的需要,它就必須等待并釋放掉監視器,從而允許其它線程進入,關于線程協作的問題參考下面的小節。
3.3 監視器實現協作
?????? 上面小節主要說明了生產者和消費者對緩沖區的互斥訪問關系,但是沒有詳細談到“wait & Release the Monitor”這個活動,這個主要牽涉了監視器實現的線程間的協作關系。
生產者和消費者通過監視器協作完成生產者消費者問題的活動圖如圖三所示。
?
?
圖三、生產者-消費者之間的協作
?
重點關注圖中的綠色部分,擁有監視器的線程檢測到當前緩沖區不符合自己要求的情況下“wait & Release the Monitor”,這樣這個線程就釋放掉了該監視器,并且進入到等待區。假設這個線程是生產者Thread_p,此時無論消費者線程Thread_c處于入口區還是等待區,Thread_c都可能獲得該監視器并繼續執行。Thread_c消費完產品并設置好緩沖區之后,它通知(notify/notifyAll)等待區的線程,正在等待(wait)的線程要求的條件滿足后可以競爭獲取監視器,并繼續執行。
注意,等待線程并不是收到notify消息立即就能獲取監視器,還要等發送notify消息的線程離開臨界區(此時,已經釋放監視器)時它才能競爭獲取。這里的“競爭獲取”指的是處于入口區和等待區的線程按照某種調度策略被選擇進入監視器,這種策略可以是用先入先出(FIFO)隊列實現的先來先服務管理,但采用哪種實現要看虛擬機的具體實現。因為這種等待線程的競爭獲取監視器現象的存在,等待線程在擁有監視器之后要判斷當前條件是否真的滿足需要——狀態有可能被先于它獲得監視器的其它線程改變。
四、JVM線程同步的實現
JVM通過對象鎖實現監視器的模型的線程同步機制。其實現是通過在JVM內部為每個對象和類都關聯一個鎖;語言層次上用同步方法或同步語句標識臨界區,每個對象都實現等待/通知方法等方式來通過實現線程同步的。
4.1 JVM線程模型
Java中的線程是在用戶級實現的,即,在操作系統看來JVM是一個進程,而Java線程是JVM內部實現的,對OS內核來說是透明的。這種實現可以利用JVM對Java線程執行期的完全控制在JVM和Java語言上實現線程的同步。其實現也就是圖四中的2)用戶級線程(User Level Thread/ULT)。
?
?
?
圖四中,用戶級線程(User Level Threads/ULT),對OS內核來說是透明的;內核級線程(Kernel Level Threads/KLT)在用戶空間和內核空間有相應線程的對應關系。JVM的一個實例,在內核空間只有一個OS進程與其對應,而Java內部實現的線程對OS來說都是不可見的,是實現在JVM內部的用戶級線程。
4.2 對象鎖
對JVM內部非私有數據的保護,JVM采用的是為每一個這樣的數據對象都關聯一個對象鎖,這些數據主要有堆中的對象實例和方法區中的類變量。這也就是為每一個對象關聯一個對象鎖,來實現監視器機制的對某個對象的互斥訪問和基于某個條件的協作工作。類鎖的實現采用的是對象鎖,不同的是,對象鎖是針對java.lang.Object對象,而類鎖是針對java.lang.Class對象,也就是類的實例。
JVM內部對每一個對象鎖都有一個相應的計數,
- 如果該計數為0,則它沒有被鎖,可以由訪問它的線程來加鎖;
- 如果該對象鎖被別的線程鎖定,則現在訪問它的線程被掛起等待,直到鎖定它的線程釋放該對象鎖,并且計數為0;
- 一個線程已經擁有了一個對象的對象鎖,如果再次訪問這個對象,則可以重入,并且這個對象鎖對應的計數加一;
- 擁有對象鎖的線程釋放對象鎖的時候,對象鎖對應的計數減一;當減到計數為零時,該鎖可被等待的線程競爭擁有。
由對象鎖的特性可以看出,利用JVM的對象鎖就實現了對被對象鎖保護對象的互斥訪問,是監視器模型的線程的互斥實現。當前鎖定一個對象的線程也可以因等待(wait)某個條件而釋放該對象鎖;擁有對象鎖的線程也可以在別的線程等待的某個條件滿足之后通知它(notify)或它們(notifyAll),這也就實現了線程間的協作。
目前已經討論了JVM如何實現線程同步的,但是還不知道如何進入/退出臨界區,以及如何通知等待的線程實現線程協作的,這些都在Java語言上給予了支持,本文在下面章節具體介紹。
4.3 Java語言對線程同步的支持
Java語言上對線程同步的支持主要有對臨界區的標識,和線程協作的支持。
4.3.1 同步方法與同步語句
Java語言對臨界區的標識是通過同步方法(Synchronized Method)和同步語句(Synchronized Statements)實現的。Java線程在進入這些同步方法或同步語句標識的臨界區開始的地方申請被保護對象的對象鎖;離開臨界區的時候(包括出現異常而離開的時候)釋放掉該對象鎖;如果該對象鎖已經被別的線程鎖定,則當前進入的線程被掛起等待。這一切是在JVM內部實現的,Java程序中要做的是用同步方法或同步語句標識臨界區,并指名被保護對象,也就是對象鎖所對應的對象。
同步方法是在一個類的方法的前面用synchronized關鍵字聲明,這樣標識了一個臨界區,在線程訪問這個類的對象的該方法的時候,就遵從鎖對象的管理機制。同步語句是把某條或某幾條語句用synchronized關鍵字標識出并指名同步語句所針對的對象。
同步方法和同步語句實現的機理是一樣的,所不同的只是它們所標識區域的粒度不同,同步方法的標識的鎖的粒度大于同步語句的,線程等待該鎖的時間也就比較久,但是實現會比較容易,;同步方法可以指定其所管理的對象,比較靈活。所以對于同步方法或是同步語句的選擇,一般原則是,對性能要求不是很高的應用層程序采用同步方法,而調度性能要求較高的底層應用,宜采用同步語句,并盡量減小其所保護的范圍,當然這在提高性能的同時增加了設計的復雜度。所以這要根據你所具體應用場景的各項因素來平衡選擇。
4.3.2 協作——wait & notify/notifyAll
Java語言的每個對象(都是java.lang.Object的子類)都實現了線程協作的方法,只是這些方法只有在同步方法或同步語句所標識的臨界區內才能被調用,也就是調用這些方法的時候,相對應的對象已經被加鎖。這種協作方式,也就如前文所述,
- 擁有對象鎖(監視器)的線程調用wait釋放該對象鎖并等待再次進入;
- 擁有對象鎖的線程執行過程中,別的線程等待的條件滿足,則通知(notify)等待的線程或通知所有(notifyAll)等待的線程。
wait & notify/notifyAll的原型聲明如下:
?
public final void wait() throws InterruptedException
public final native void wait(long timeout) throws InterruptedException;
public final void wait(long timeout, int nanos) throws InterruptedException
public final native void notify();
public final native void notifyAll();
?
等待某個對象鎖的時候,可以指定等待的時間,超時的話,自動退出等待。
當明確知道等待區內只有一個等待線程的時候,才應該使用notify,否則就應該使用notifyAll,讓JVM采用相應的調度策略來決定選擇哪個等待該對象鎖的線程被喚起。這樣就可由JVM來保證避免某個線程無限制等待的饑餓現象,而不需要用戶來關注。
五、利用JVM線程同步解決生產者消費者問題
本節以生產者消費者的實例說明JVM線程同步的設計。
5.1 生產者消費者問題相關類層次
生產者消費者問題相關類層次如下圖所示
?
?
圖五、生產者消費者問題相關類層次圖
?
生產者(Producer)和消費者(Consumer)線程引用同一個緩沖區(Buffer)實例。緩沖區可以判斷當前是否為空(isNull);非空情況下,可以從中得到產品并將其清空(getProduct);Buffer為空的情況下,可以放置產品進去(setProduct)。
5.2 生產者線程——threadSynch.ProducerConsumer.Producer
生產者線程不停地生產產品,如果緩沖區為空,放置產品到緩沖區。Producer Override Thread的run()方法,這樣在調用線程的start()方法的時候,JVM線程調度機制會自動調用線程的run()方法。下面程序段是Producer.run()方法。
?
??? public void run() {
??????? super.run();
??????? while (true) {
??????????? execute();
??????? }
??? }
?
execute()是生產者的循環執行體,實現的是圖三的生產者的活動,代碼如下:
??? private void execute() {
??????? generateNewProduct();
??????? System.out.println("[Producer] produced a new product: " + product);
??????? synchronized (buffer) {
??????????? System.out.println("[Producer] Owned the buffer's monitor!");
??????????? while (!buffer.isNull()) {
??????????????? System.out.println("[Producer] release the monitor and wait!");
??????????????? try {
??????????????????? buffer.wait();
??????????????? } catch (InterruptedException e) {
??????????????????? e.printStackTrace();
??????????????? }
??????????????? System.out.println("[Producer] re-owned the monitor!");
??????????? }
??????????? System.out.println("[Producer] put the product (" + product
??????????????????? + ") into the buffer!");
??????????? buffer.setProduct(product);
??????????? System.out.println("[Producer] notify other threads waiting on the monitor!");
??????????? buffer.notifyAll();
??????????? System.out.println("[Producer] to release the monitor!");
??????? }
??? }
?
generateNewProduct()利用java.util.Random產生一個隨機數代碼生產者生產的產品。
??? private void generateNewProduct() {
??????? int prd = product;
??????? while ((prd = (new Random()).nextInt(100)) == product)
??????????? ;
??????? product = prd;
??? }
?
5.3 消費者線程——threadSynch.ProducerConsumer.Consumer
消費者線程不停地查詢緩沖區內是否有產品,如果緩沖區內有產品,則從中取出產品并清緩沖區。Consumer Override Thread.run()方法,這樣在調用線程的start()方法的時候,JVM線程調度機制會自動調用線程的run()方法。Run()的實現同生產者線程,不同的是循環執行體execute(),其實現的是圖三所示的消費者的活動。
?
??? private void execute() {
??????? synchronized (buff) {
??????????? System.out.println("[Consumer] Owned the monitor!");
??????????? while (buff.isNull()) {
??????????????? System.out.println("[Consumer] release the monitor and wait!");
??????????????? try {
??????????????????? buff.wait();
??????????????? } catch (InterruptedException e) {
??????????????????? ??? e.printStackTrace();
??????????????? }
??????????????? System.out.println("[Consumer] re-owned the monitor!");
??????????? }
??????????? product = buff.getProduct();
??????????? System.out.println("[Consumer] get a product (" + product
??????????????????? + ") from the buffer!");
??????????? System.out.println("[Consumer] notify others waiting on the monitor!");
??????????? buff.notifyAll();
??????????? System.out.println("[Consumer] to release the monitor!");
??????? }
??????? System.out.println("[Consumer] consume the product: " + product);
??? }
?
5.4 主程序——threadSynch.ProducerConsumer. ProducerConsumer
主程序ProducerConsumer創建Buffer以及生產者和消費者線程的實例,并啟動生產者和消費者線程。
?
package threadSynch.ProducerConsumer;
public class ProducerConsumer {
??? private static Producer producer;
??? private static Consumer consumer;
??? private static Buffer buffer;
??? public static void main(String[] args) {
?????? buffer = new Buffer(0);
?????? producer = new Producer(buffer);
?????? consumer = new Consumer(buffer);
?????? consumer.start();
?????? producer.start();
??? }
}
?
5.5 程序運行時的一個快照
下面是上述程序運行時的一個快照,并分別以綠色和藍色標識生產者和消費者的輸出:
?
[Consumer] Owned the monitor!?????????????????????????????????????????????? (01)
[Consumer] release the monitor and wait!??????????????????????????????????? (02)
[Producer] produced a new product: 43??????????? ???????????????????????????(03)
[Producer] Owned the buffer's monitor!????????????????????????????????????? (04)
[Producer] put the product (43) into the buffer!??????????????????????????? (05)
[Producer] notify other threads waiting on the monitor!??? ?????????????????(06)
[Producer] to release the monitor!????????????????????????????????????????? (07)
[Consumer] re-owned the monitor!??????????????????????????????????????????? (08)
[Consumer] get a product (43) from the buffer!?????????????????????? ???????(09)
[Consumer] notify others waiting on the monitor!??????????????????????????? (10)
[Consumer] to release the monitor!????????????????????????????????????????? (11)
[Consumer] consume the product: 43????????????????????????????????????????? (12)
[Consumer] Owned the monitor!?????????????????????????????????????????????? (13)
[Producer] produced a new product: 70?????????????????????????????????????? (14)
[Consumer] release the monitor and wait!??????????????????????????????????? (15)
[Producer] Owned the buffer's monitor!????????????????????????????????????? (16)
[Producer] put the product (70) into the buffer!??????????????????????????? (17)
[Producer] notify other threads waiting on the monitor!???????????????????? (18)
[Producer] to release the monitor!????????????????????????????????????????? (19)
[Producer] produced a new product: 43?????????????????????????????????????? (20)
[Producer] Owned the buffer's monitor!????????????????????????????????????? (21)
[Producer] release the monitor and wait!??????????????????????????????????? (22)
[Consumer] re-owned the monitor!??????????????????????????????????????????? (23)
[Consumer] get a product (70) from the buffer!????????????????????????????? (24)
[Consumer] notify others waiting on the monitor!??????????????????????????? (25)
[Consumer] to release the monitor!????????????????????????????????????????? (26)
[Consumer] consume the product: 70????????????????????????????????????????? (27)
[Consumer] Owned the monitor!????????????????? ?????????????????????????????(28)
[Consumer] release the monitor and wait!??????????????????????????????????? (29)
[Producer] re-owned the monitor!??????????????????????????????????????????? (30)
[Producer] put the product (43) into the buffer!???????? ???????????????????(31)
[Producer] notify other threads waiting on the monitor!???????????????????? (32)
[Producer] to release the monitor!????????????????????????????????????????? (33)
[Producer] produced a new product: 34????????????????????????????? ?????????(34)
[Producer] Owned the buffer's monitor!????????????????????????????????????? (35)
[Producer] release the monitor and wait!??????????????????????????????????? (36)
[Consumer] re-owned the monitor!??????????????????????????????????????????? (37)
[Consumer] ――――――?????????????????????????????????????????????????????????? (38)
[Producer] ――――――?????????????????????????????????????????????????????????? (39)
?
生產者消費者相關聯的對象的簡寫表示:Per-生產者;Cer-消費者;B-緩沖區;M-緩沖區相關聯的監視器;Px(x = 1, 2, …)-產品。結合圖三的生產者和消費者的活動圖,可以解釋上面的輸出快照。
- 消費者Cer首先運行,獲得監視器M,因緩沖區B內當前還沒有產品P,所以Cer釋放M并等待[Line 1, 2]。
- 生產者Per生產了一個產品P1,在獲得M之后,放置P1到B并通知Cer,釋放M[Line 3-7]。
- Cer重新獲得M之后,從B中得到P1并清空B,通知其它線程當前B可用,釋放M,消費產品P1(因為P1已經被Cer獲得,所以消費P1不需要在臨界區內完成),重新獲得M(線程調度的作用)[Line 8-13]。
- Per生產一個新產品P2(雖然Per當前未獲得M,但生產產品是不需要在臨界區的,當JVM線程調度運行Per的時候,它仍然可以生產產品)[Line 14]。
- P2并未被放到B,所以Cer釋放M并等待[Line 15]。
- Per現在可獲得M[16],并放置P2到B[17],然后喚醒等待M的線程[18]并釋放M[19];當前Cer并未獲得調度運行,所以Per繼續生產P3[20];Per獲得M并試圖放置P3到B[21],但此時Cer還未取走P2,所以Per釋放M并等待[22];
- Cer…[23, …]
- Per…[line…]
<!--[if !supportLineBreakNewLine]-->
<!--[endif]-->
六、總結
多線程有有效的利用了計算機的最珍貴的CPU資源,但在計算性能提高的基礎上的同時,也增加了設計的復雜度。Java利用JVM對運行期的控制,實現了JVM內的線程模型,并簡化了實現了線程間的同步問題,對編寫Java程序的人員來說,開發的效率顯著提高。
任何設計決策都不能用絕對的孤立的評價角度來看,它應該是各種因素的綜合。JVM線程同步模型也是一樣,Java開發者實現簡單的代價也就喪失了靈活性。比如要在同一個類的多個方法之間實現同步,用同步方法或同步語句來實現就顯得力不從心了,如果增加監視器來實現,處理不當就又可能引起死鎖(Dead Lock)。
關于其它同步方法,Doug?Lea實現了一個Java語言工具包。現在這個包已經加入處于JCP控制下的JSR標準。SUN Java SE 1.5實現中也已經加入了這部分代碼,有興趣的讀者可以參閱。
文中所描述的生產者消費者問題的實例代碼可與本文作者聯系索取。
?
參考資料及進一步閱讀
1) 孫鐘秀,費翔林,駱斌,謝立. 操作系統教程,第三版. 高等教育出版社,2003.8
2) Abraham Silberschatz, Peter Baer Galvin, Greg Gagne. Operating System Concepts, 6th Edition. John Wiley & Sons, Inc/高等教育出版社影印, 2002.5
3) David R. Butenhof/于磊,曾剛. Programming with POSIX Threads. Addison Wesley/中國電力出版社, 2003
4) Bill Venners著/曹曉鋼,蔣靖譯. Inside the Java Virtual Machine, 2nd edition. McGraw-Hill/機械工業出版社, 2003
5) Ken Arnold, James Gosling, David Holmes. The Java Programming Language, 3rd Edition. Addison Wesley/中國電力出版社影印, 2003.5
6) Michael L. Scott著/裘宗燕譯. Programming Language Pragmatics. Elsevier/電子工業出版社, 2005.3
關于作者
田海立,碩士,國家系統分析師,CSAI專業顧問。您可以通過 haili.tian@csai.cn 或 haili.tian@gmail.com 與他聯系,到 http://blog.csdn.net/thl789/ 看他最新的文章。
?
(本文可自由轉載,但請給出原文鏈接: http://blog.csdn.net/thl789/archive/2005/12/30/566494.aspx)。
?
總結
以上是生活随笔為你收集整理的解析JVM线程同步机制的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: velocity显示List与Map的方
- 下一篇: FilterDispatcher is