1. 程式人生 > >Java併發之深入分析synchronized的實現原理

Java併發之深入分析synchronized的實現原理

稍微進行了整合

目前在Java中存在兩種鎖機制:synchronized和Lock,Lock介面及其實現類是JDK5增加的內容,synchronized是個重量級鎖,是解決併發問題的一種最常用的方法,也是最簡單的一種方法,Java SE1.6對其進行了優化。

synchronized作用主要有三個:

1)確保執行緒互斥的訪問同步程式碼

2)保證共享變數的修改能夠及時可見

3)有效解決重排序問題

Java中每一個物件都可以作為鎖,這是synchronized實現同步的基礎:

1)普通同步方法,鎖是當前例項物件

2)靜態同步方法,鎖是當前類的class物件

3)同步方法塊,鎖是括號裡的物件

當一個執行緒訪問同步程式碼塊時,它需要得到鎖才能執行同步程式碼,退出或拋異常時必須要釋放鎖,它是如何實現的呢?我們先來看一段簡單的程式碼:

public class SynchronizedTest {
    public synchronized void test1(){
    }
    public void test2(){
        synchronized(this){
    }
    }
}
monitorenter指令插入到同步程式碼塊的開始位置,monitorexit指令插入到同步程式碼塊的結束位置,JVM需要保證每一個monitorenter都有一個monitorexit與之相對應。任何物件都有一個monitor與之相關聯,當且一個monitor被持有之後,他將處於鎖定狀態。執行緒執行到monitorenter指令時,將會嘗試獲取物件所對應的monitor所有權,即嘗試獲取物件的鎖。

synchronized方法會被翻譯成普通的方法呼叫和返回指令,如:invokevirtual和areturn指令,在VM的位元組碼層面沒有任何特別的指令來實現被synchronized修飾的方法,而是在Class檔案的方法表中將該方法的access_flags中的synchronized標誌位置為1,並表示該方法是同步方法並使用呼叫該方法的物件或該方法所屬的Class在JVM的內部物件表示Klass做為鎖物件。

當多個執行緒同時請求某個物件監視器時,物件監視器會設定幾種狀態用來區分請求的執行緒:

Contention List所有請求鎖的執行緒將被首先放置到該競爭佇列
Entry ListContention List中那些有資格成為候選人的執行緒被移到Entry List中
Wait Set那些呼叫wait方法被阻塞的執行緒被放置到Wait Set中
OnDeck任何時刻最多隻能有一個執行緒正在競爭鎖,該執行緒稱為OnDeck
Owner獲得鎖的執行緒成為Owner
!Owner釋放鎖的執行緒

下圖反映了狀態轉換關係


新請求鎖的執行緒將首先被加入到ContentionList中,當某個擁有鎖的執行緒呼叫unlock之後,如果發現EntryList為空,則從ContentionList中移動執行緒到EntryList,下面說明ContentionList和EntryList的實現方式:

1)ContentionList虛擬佇列

ContentionList是由Node及其next指標邏輯構成,並不存在一個Queue的資料結構。ContentionList是一個後進先出(LIFO)的佇列,每次新加入Node時都會在隊頭進行,通過CAS改變第一個節點的指標為新增節點,同時設定新增節點的next指向後續節點,而取得操作則發生在隊尾。顯然,該結構是個Lock-Free佇列。

因為只有Owner執行緒才能從隊尾取元素,也即執行緒出列操作無爭用,當然也就避免了CAS的ABA問題。


2)EntryList

EntryList與ContentionList邏輯上同屬等待佇列,ContentionList會被執行緒併發訪問,為了降低對ContentionList隊尾的爭用,而建立EntryList。Owner執行緒在unlock時會從ContentionList中遷移執行緒到EntryList,並會指定EntryList中的某個執行緒(一般是Head)為OnDeck執行緒。Owner執行緒並不是把鎖傳遞給OnDeck執行緒,只是把競爭鎖的權力交給OnDeck,OnDeck執行緒需要重新競爭鎖,這樣做雖然犧牲了一定的公平性,但極大的提高了整體吞吐量。在Hotspot中把OnDeck的選擇行為稱作“競爭切換”。

OnDeck執行緒獲得鎖後變為Owner執行緒,無法獲得鎖則會依然留在EntryList中,考慮到公平性,在EntryList中的位置不發生變化(依然在隊頭)。如果Owner執行緒被wait方法阻塞,則轉移到WaitSet佇列中,如果在某個時刻被notify/notifyAll喚醒,則再次轉移到EntryList。

介紹一下CAS(Compare-And-Swap)

是一條CPU的原子指令,其作用是讓CPU比較後原子地更新某個位置的值,實現方式是基於硬體平臺的彙編指令實現的,JVM只是封裝了彙編呼叫。

CAS為什麼會引起本地延遲?

下圖為SMP(對稱多處理器)架構


所有的CPU會共享一條系統匯流排(BUS),考此匯流排連線主存。每個核都有自己的一級快取,各核相對於BUS對稱分佈,因此這種結構被稱為“對稱多處理器”。

Core1和Core2可能會同時把主存中某個位置的值Load到自己的L1 Cache中,當Core1在自己的L1 Cache中修改這個位置的值時,會通過匯流排,使Core2中L1 Cache對應的值“失效”,而Core2一旦發現自己L1 Cache中的值失效(稱為Cache命中缺失)則會通過匯流排從記憶體中載入該地址最新的值,大家通過匯流排的來回通訊稱為“Cache一致性流量”,因為總 線被設計為固定的“通訊能力”,如果Cache一致性流量過大,匯流排將成為瓶頸。而當Core1和Core2中的值再次一致時,稱為“Cache一致 性”,從這個層面來說,鎖設計的終極目標便是減少Cache一致性流量。

而CAS恰好會導致Cache一致性流量,如果有很多執行緒都共享同一個物件,當某個Core CAS成功時必然會引起匯流排風暴,這就是所謂的本地延遲,本質上偏向鎖就是為了消除CAS,降低Cache一致性流量。

深入前需要了解兩個重要概念:Java物件頭和Monitor(是實現synchronized的基礎

synchronized用的鎖是存在Java物件頭裡的,Hotsport虛擬機器的物件頭主要包括兩部分資料:Mark Word(標記欄位)、Klass Pointer(型別指標)。Klass Pointer是物件指向它類元資料的指標,虛擬機器通過這個指標來確定這個物件是哪個類的例項,Mark Word用於儲存物件自身的執行時資料,它是實現輕量級鎖和偏向鎖的關鍵,下面將重點闡述:
Mark Word用於儲存物件自身的執行時資料,如雜湊碼(HashCode)、GC分代年齡、鎖狀態標誌、執行緒持有的鎖、偏向執行緒 ID、偏向時間戳等等。Java物件頭一般佔有兩個機器碼(在32位虛擬機器中,1個機器碼等於4位元組,也就是32bit),但是如果物件是陣列型別,則需要三個機器碼,因為JVM虛擬機器可以通過Java物件的元資料資訊確定Java物件的大小,但是無法從陣列的元資料來確認陣列的大小,所以用一塊來記錄陣列長度。
下圖是Java物件頭的儲存結構(32位虛擬機器):
Owner
EntryQ
RcThis
Nest
HashCode
Candidate

利用javap工具檢視生成的class檔案資訊來分析Synchronize的實現 


從上面可以看出,同步程式碼塊是使用monitorenter和monitorexit指令實現的,同步方法(在這看不出來需要看JVM底層實現)依靠的是方法修飾符上的ACC_SYNCHRONIZED實現。 

同步程式碼塊:

monitorenter指令插入到同步程式碼塊的開始位置,monitorexit指令插入到同步程式碼塊的結束位置,JVM需要保證每一個monitorenter都有一個monitorexit與之相對應。任何物件都有一個monitor與之相關聯,當且一個monitor被持有之後,他將處於鎖定狀態。執行緒執行到monitorenter指令時,將會嘗試獲取物件所對應的monitor所有權,即嘗試獲取物件的鎖。

同步方法:

synchronized方法會被翻譯成普通的方法呼叫和返回指令,如:invokevirtual和areturn指令,在VM的位元組碼層面沒有任何特別的指令來實現被synchronized修飾的方法,而是在Class檔案的方法表中將該方法的access_flags中的synchronized標誌位置為1,並表示該方法是同步方法並使用呼叫該方法的物件或該方法所屬的Class在JVM的內部物件表示Klass做為鎖物件。

深入前需要了解兩個重要概念:Java物件頭和Monitor(是實現synchronized的基礎)

Java物件頭

synchronized用的鎖是存在Java物件頭裡的,Hotsport虛擬機器的物件頭主要包括兩部分資料:Mark Word(標記欄位)、Klass Pointer(型別指標)。Klass Pointer是物件指向它類元資料的指標,虛擬機器通過這個指標來確定這個物件是哪個類的例項,Mark Word用於儲存物件自身的執行時資料,它是實現輕量級鎖和偏向鎖的關鍵,下面將重點闡述:

Mark Word

Mark Word用於儲存物件自身的執行時資料,如雜湊碼(HashCode)、GC分代年齡、鎖狀態標誌、執行緒持有的鎖、偏向執行緒 ID、偏向時間戳等等。Java物件頭一般佔有兩個機器碼(在32位虛擬機器中,1個機器碼等於4位元組,也就是32bit),但是如果物件是陣列型別,則需要三個機器碼,因為JVM虛擬機器可以通過Java物件的元資料資訊確定Java物件的大小,但是無法從陣列的元資料來確認陣列的大小,所以用一塊來記錄陣列長度。

下圖是Java物件頭的儲存結構(32位虛擬機器):

25Bit4Bit1Bit2Bit
物件的hashCode物件的分代年齡是否偏向鎖鎖標誌位

synchronized使用的鎖是存放在Java物件頭裡面,具體位置是物件頭裡面的MarkWord,MarkWord裡預設資料是儲存物件的HashCode等資訊,但是會隨著物件的執行改變而發生變化,不同的鎖狀態對應著不同的記錄儲存方式,可能值如下所示:


Monitor

什麼是Monitor?我們可以把它理解為一個同步工具,也可以描述為一種同步機制,它通常被描述為一個物件。

萬物皆物件,所有的Java物件是天生的Monitor,每個Java物件都有成為Monitor的潛質,因為在Java的設計中,每個Java物件自帶一把看不見的鎖,它叫內部鎖或者Monitor鎖。

Monitor是執行緒私有的資料結構。每個執行緒都有一個可用的monitor record列表。同時還有一個全域性的可用列表。每一個被鎖住的物件都會和monitor關聯(物件頭的MarkWord中的LockWord指向monitor的起始地址),同時monitor中有一個Owner欄位存放擁有該鎖的執行緒的唯一標識,表示該鎖被這個執行緒佔用。

其結構如下:

Owner:初始時為null表示當前沒有任何執行緒擁有該monitor record,當執行緒成功擁有該鎖後儲存執行緒唯一標識,當鎖被釋放時又設定為null

EntryQ:關聯一個系統互斥鎖(semaphore),阻塞所有試圖鎖住monitor record失敗的執行緒。

RcThis:表示blocked或waiting在該monitor record上的所有執行緒的個數。

Nest:用來實現重入鎖的計數。

HashCode:儲存從物件頭拷貝過來的hashcode值(可能還包括GC age)

Candidate:用來避免不必要的阻塞或等待執行緒喚醒,因為每次只有一個執行緒能成功擁有鎖,如果每次前一個釋放鎖的執行緒喚醒所有正在阻塞或等待的執行緒,會引起不必要的上下文切換(從阻塞到就緒然後因為競爭鎖失敗又被阻塞),導致效能嚴重下降。它只有兩種可能的值,0表示沒有需要喚醒的執行緒,1表示要喚醒一個繼任執行緒要競爭鎖。

鎖的優化

JDK1.6對鎖的實現引入了大量優化,如自旋鎖、適應性自旋鎖、鎖消除、鎖粗化、偏向鎖、輕量級鎖等技術來減少鎖操作的開銷。

鎖主要存在四種狀態,依次是:無鎖狀態、偏向鎖狀態、輕量級鎖狀態、重量級鎖狀態。他們會隨著競爭的激烈而逐漸升級。

注意:鎖可以升級不可以降級,這種策略是為了提高獲得鎖和釋放鎖的效率。

無鎖 --> 偏向鎖 --> 輕量級 --> 重量級

自旋鎖

執行緒的阻塞和喚醒需要CPU從使用者態轉為核心態,頻繁的阻塞和喚醒對CPU來說是一件負擔很重的工作,勢必會給

系統的併發效能帶來很大的壓力。同時我們發現在許多應用上面,物件鎖的鎖狀態只會持續很短的一段時間,為了

這一段很短的時間頻繁地阻塞和喚醒執行緒是非常不值得的。

所以引入自旋鎖。那麼,什麼是自旋鎖呢?

自旋鎖就是讓該執行緒等待一段時間,不會被立即掛起。看持有鎖的執行緒是否會很快釋放鎖。

怎麼等待呢?執行一段無意義的迴圈即可(自旋)。

自旋不能替代阻塞,先不說對處理器數量的要求(多核,貌似現在沒有單核的處理器了),雖然它可以避免線

切換帶來的開銷,但是它佔用了處理器的時間。如果持有鎖的執行緒很快就釋放了鎖,那麼自旋的效率就非常

好;反之,自旋的執行緒就會白白消耗掉處理的資源,它不會做任何有意義的工作,典型的佔著茅坑不拉屎,

這樣反而會帶來效能上的浪費。

所以說,自旋等待的時間(自旋的次數)必須要有一個限度,如果自旋超過了定義的時間仍然沒有獲取到鎖,

則應該被掛起。自旋鎖在JDK 1.4.2中引入,預設關閉,但是可以使用-XX:+UseSpinning開開啟,在JDK1.6

預設開啟。同時自旋的預設次數為10次,可以通過引數-XX:PreBlockSpin來調整。

如果通過引數-XX:preBlockSpin來調整自旋鎖的自旋次數,會帶來諸多不便。假如我將引數調整為10,但是

系統很多執行緒都是等你剛剛退出的時候就釋放了鎖(假如你多自旋一兩次就可以獲取鎖),你是不是很尷尬?

於是JDK1.6引入自適應的自旋鎖,讓虛擬機器會變得越來越聰明。

適應自旋鎖

JDK 1.6引入了更加聰明的自旋鎖,即自適應自旋鎖。所謂自適應就意味著自旋的次數不再是固定的,它是由

一次在同一個鎖上的自旋時間及鎖的擁有者的狀態來決定。執行緒如果自旋成功了,那麼下次自旋的次數會

加多因為虛擬機器認為既然上次成功了,那麼此次自旋也很有可能會再次成功,那麼它就會允許自旋等待持續

的次數更多。反之,如果對於某個鎖,很少有自旋能夠成功的,那麼在以後要或者這個鎖的時候自旋的次數會

減少甚至省略掉自旋過程,以免浪費處理器資源。有了自適應自旋鎖,隨著程式執行和效能監控資訊的不斷完

善,虛擬機器對程式鎖的狀況預測會越來越準確,虛擬機器會變得越來越聰明。

鎖消除

為了保證資料的完整性,我們在進行操作時需要對這部分操作進行同步控制,但是在有些情況下,JVM檢測到

不可能存在共享資料競爭,這是JVM會對這些同步鎖進行鎖消除。鎖消除的依據是逃逸分析的資料支援。

如果不存在競爭,為什麼還需要加鎖呢?

所以鎖消除可以節省毫無意義的請求鎖的時間。變數是否逃逸,對於虛擬機器來說需要使用資料流分析來確定,

但是對於我們程式設計師來說這還不清楚麼?我們會在明明知道不存在資料競爭的程式碼塊前加上同步嗎?但是有時

候程式並不是我們所想的那樣?我們雖然沒有顯示使用鎖,但是我們在使用一些JDK的內建API時,如

StringBuffer、Vector、HashTable等,這個時候會存在隱形的加鎖操作。

比如StringBuffer的append()方法,Vector的add()方法:

public void test(){
     Vector<String> vector = new Vector<String>();
     for(int i=0;i<10;i++){
          vector.add(i+" ");    
     }
     System.out.println(vector);
}

在執行這段程式碼時,JVM可以明顯檢測到變數vector沒有逃逸出test方法之外,所以JVM可以大膽地將vector內部的加鎖操作消除。

鎖粗化

我們知道在使用同步鎖的時候,需要讓同步塊的作用範圍儘可能小,僅在共享資料的實際作用域中才進行同步。

這樣做的目的是為了使需要同步的運算元量儘可能縮小,如果存在鎖競爭,那麼等待鎖的執行緒也能儘快拿到鎖。

在大多數的情況下,上述觀點是正確的。但是如果一系列的連續加鎖解鎖操作,可能會導致不必要的效能損耗,所以引入鎖粗化的概念。 

那什麼是鎖粗化?

鎖粗化就是將多個連續的加鎖、解鎖操作連線在一起,擴充套件成一個範圍更大的鎖。如上面例項:

vector每次add的時候都需要加鎖操作,JVM檢測到對同一個物件(vector)連續加鎖、解鎖操作,

會合並一個更大範圍的加鎖、解鎖操作,即加鎖解鎖操作會移到for迴圈之外。

輕量級鎖

這種鎖實現的背後基於這樣一種假設,即在真實的情況下我們程式中的大部分同步程式碼一般都處於無鎖競爭狀

態(即單執行緒執行環境),在無鎖競爭的情況下完全可以避免呼叫作業系統層面的重量級互斥鎖,取而代之的

是在monitorenter和monitorexit中只需要依靠一條CAS原子指令就可以完成鎖的獲取及釋放。當存在鎖競爭的

情況下,執行CAS指令失敗的執行緒將呼叫作業系統互斥鎖進入到阻塞狀態,當鎖被釋放的時候被喚醒。

獲取鎖步驟如下:

1)判斷當前物件是否處於無鎖狀態(hashcode、0、01),若是,則JVM首先將在當前執行緒的棧幀中建立一

個名為鎖記錄(Lock Record)的空間,用於儲存鎖物件目前的Mark Word的拷貝(官方把這份拷貝加了一個

Displaced字首,即Displaced Mark Word);否則執行步驟(3);

2)JVM利用CAS操作嘗試將物件的Mark Word更新為指向Lock Record的指正,如果成功表示競爭到鎖,則

將鎖標誌位變成00(表示此物件處於輕量級鎖狀態),執行同步操作;如果失敗則執行步驟(3);

3)判斷當前物件的Mark Word是否指向當前執行緒的棧幀,如果是則表示當前執行緒已經持有當前物件的鎖,則

直接執行同步程式碼塊;否則只能說明該鎖物件已經被其他執行緒搶佔了,這時輕量級鎖需要膨脹為重量級鎖,鎖

標誌位變成10,後面等待的執行緒將會進入阻塞狀態;

釋放輕量級鎖也是通過CAS操作來執行的。主要步驟如下:

相關推薦

Java併發深入分析synchronized實現原理

稍微進行了整合目前在Java中存在兩種鎖機制:synchronized和Lock,Lock介面及其實現類是JDK5增加的內容,synchronized是個重量級鎖,是解決併發問題的一種最常用的方法,也是最簡單的一種方法,Java SE1.6對其進行了優化。synchroniz

【死磕Java併發】- 深入分析volatile的實現原理

通過前面一章我們瞭解了synchronized是一個重量級的鎖,雖然JVM對它做了很多優化,而下面介紹的volatile則是輕量級的synchronized。如果一個變數使用volatile,則它比使用synchronized的成本更加低,因為它不會引起執行緒上下文的切換和排程。Java語言

【死磕Java併發】--深入分析volatile的實現原理

通過前面一章我們瞭解了synchronized是一個重量級的鎖,雖然JVM對它做了很多優化,而下面介紹的volatile則是輕量級的synchronized。如果一個變數使用volatile,則它比使用synchronized的成本更加低,因為它不會引起執行緒上下文的切換和排

Java併發:執行緒池實現原理

一、總覽 執行緒池類ThreadPoolExecutor的相關類需要先了解: Executor:位於最頂層,只有一個 execute(Runnable runnable) 方法,用於提交任務。 ExecutorService :在 Executor 介面的基礎上添加了很多的介面方法,提交任務

Java併發程式設計-原子操作的實現原理

原子(atomic)本意時“不能被進一步分割的最小粒子”,而原子操作(atomic operation)意為“不可被中斷的一個或一系列操作”。 Java 如何實現原子操作 在 Java 中可以通過鎖和迴圈 CAS 的方式實現原子操作。 1、使用迴圈 CAS 實現原子操作 JVM 中的 CAS 操作

Java併發機制及鎖的實現原理

Java併發程式設計概述 併發程式設計的目的是為了讓程式執行得更快,但是,並不是啟動更多的執行緒就能讓程式最大限度地併發執行。在進行併發程式設計時,如果希望通過多執行緒執行任務讓程式執行得更快,會面臨非常多的挑戰,比如上下文切換的問題、死鎖的問題,以及受限於硬體和軟體的資源

Java進階--深入理解ArrayList實現原理

ArrayList簡介 ArrayList就是動態陣列,用MSDN中的說法,就是Array的複雜版本,它提供了動態的增加和減少元素,實現了Collection和List介面,可以靈活的設定陣列的大小。要注意的是ArrayList並不是執行緒安全的,因此一般建議

Java併發機制底層——Volatile的實現原理

引言 在多執行緒併發程式設計中synchronized和Volatile都扮演著重要的角色,Volatile是輕量級的synchronized,它在多處理器開發中保證了共享變數的“可見性”。可見性的意思是當一個執行緒修改一個共享變數時,另外一個執行緒能讀到這個

深入理解Java併發synchronized實現原理

關聯文章: 本篇主要是對Java併發中synchronized關鍵字進行較為深入的探索,這些知識點結合博主對synchronized的個人理解以及相關的書籍的講解(在結尾參考資料),如有誤處,歡迎留言。 執行緒安全是併發程式

深入理解 Java 併發 synchronized 實現原理

關聯文章深入理解Java型別資訊(Class物件)與反射機制深入理解Java列舉型別(enum)深入理解Java註解型別(@Annotation)深入理解Java併發之synchronized實現原理本篇主要是對Java併發中synchronized關鍵字進行較為深入的探索,這些知識點結合博主對synchro

Java併發程式設計深入執行緒池原理實現

Java執行緒池在實際的應用開發中十分廣泛。雖然Java1.5之後在JUC包中提供了內建執行緒池可以拿來就用,但是這之前仍有許多老的應用和系統是需要程式設計師自己開發的。因此,基於執行緒池的需求背景、技術要求瞭解執行緒池原理和實現,一方面可以更為深刻理解Java多執行緒開發,有助於解決業務系統中因為執行緒問題

原始碼閱讀:Java併發synchronized實現原理

執行緒安全是併發程式設計中的重要關注點,應該注意到的是,造成執行緒安全問題的主要誘因有兩點,一是存在共享資料(也稱臨界資源),二是存在多條執行緒共同操作共享資料。因此為了解決這個問題,我們可能需要這樣一個方案,當存在多個執行緒操作共享資料時,需要保證同一時刻有且

java 併發 synchronized 實現原理

在 java 開發中 synchronized 是使用的最多的工具。 表現形式 在 java 中每個物件都可以作為鎖: 對於普通同步方法,鎖是當前例項物件; 對於靜態同步方法,鎖是當前類的 Class 物件; 對於同步方法快,鎖是 Synchronized 括

Java併發(4)深入分析java執行緒池框架及實現原理(一)

先說說我個人對執行緒池的理解:執行緒池顧名思義是一個裝有很多執行緒的池子,這個池子維護著從執行緒建立到銷燬的怎個生命週期以及執行緒的分配,使用者只需要把任務提交給這個執行緒池而不用去關心執行緒池如何建立執行緒,執行緒池會自己給這些任務分配執行緒資源來完成任務。 java的E

深入分析synchronized實現原理

test 代碼塊 mage this rgs 需要 pub 釋放 javap 基礎概念   synchronized可以保證方法或者代碼塊在運行時,同一時刻只有一個方法可以進入到臨界區,同時可以保證共享變量對內存可見性。   Java中每一個對象都可以作為鎖,這是syn

Java併發(三):synchronized實現原理

一、synchronized用法 Java中的同步塊用synchronized標記。 同步塊在Java中是同步在某個物件上(監視器物件)。 所有同步在一個物件上的同步塊在同時只能被一個執行緒進入並執行操作。 所有其他等待進入該同步塊的執行緒將被阻塞,直到執行該同步塊中的執行緒退出。 (注:不要使用全

Java併發Condition的實現分析

一、Condition的概念介紹回憶 synchronized 關鍵字,它配合 Object 的 wait()、notify() 系列方法可以實現等待/通知模式。 對於 Lock,通過 Condition 也可以實現等待/通知模式。 Condition 是一個介面。 Condition 介面的實現類是

Java 併發程式設計深入學習——執行緒池及其實現原理

Java執行緒池介紹   執行緒池,從字面含義來看,是指管理一組同構工作執行緒的資源池。執行緒池是與工作佇列(work Queue)密切相關的,其中工作佇列中儲存了所有等待執行的任務。工作者執行緒(Work Thread)的任務很簡單:從工作佇列中獲取一個任務,執行任務,然

Java網際網路程式設計——深入分析java執行緒池的實現原理

月亮姨的嘮叨: 執行緒是稀缺資源,如果被無限制的建立,不僅會消耗系統資源,還會降低系統的穩定性,合理的使用執行緒池對執行緒進行統一分配、調優和監控,有以下好處: 1、降低資源消耗; 2、提高響應速度; 3、提高執行緒的可管理性。 Java1.5中引入的Executo

Java併發程式設計的藝術——volatile和synchronized實現原理

volatile volatile變數修飾的共享變數進行寫操作時候,會多出lock字首指令。 lock字首指令在多核處理器下會引發一下兩件事情: 將當前處理器快取行的資料寫回到系統記憶體。 這個寫回記