Java記憶體模型與volatile
記憶體模型描述的是程式中各變數(例項域、靜態域和陣列元素)之間的關係,以及在實際計算機系統中將變數儲存到記憶體和從記憶體取出變數這樣的低層細節。
每一個執行緒有一塊工作記憶體區,其中保留了被所有執行緒共享的主記憶體中的變數的值的拷貝。為了存取一個共享的變數,一個執行緒通常先獲取鎖定並且清除它的工作記憶體區,這保證該共享變數從所有執行緒的共享記憶體區正確地裝入到執行緒的工作記憶體區,當執行緒解鎖時保證該工作記憶體區中變數的值寫回到共享記憶體中。
下面簡單給出了規則的重要推論:
1、 適當運用同步結構,能夠正確地把一個或一組值通過共享變數從一個執行緒傳送到另一個執行緒。
2、 當一個執行緒使用一變數的值時,它獲取的值其實是由它本身或其它執行緒在變數中儲存的值。即使用程式中沒有使用正確的同步也是如此。例如,如果兩個執行緒把不同物件的引用儲存到同一個共享引用變數中,那麼該引用變數值將要麼是這個執行緒、要麼是那個執行緒所擁有的物件的引用的值,而該共享引用變數的值不可能由多個執行緒引用值組合而成(對於共享基本型別long、double除外)。
3、 在
一個變數是Java程式可以存取的一個地址,它不僅包括基本型別變數、引用型別變數,而且還包括陣列型別變數。儲存在主記憶體區的變數可以被所有執行緒共享,但一個執行緒存取另一個執行緒的引數或區域性變數是不可能的,所以我們不必擔心這些變數的執行緒安全性問題。
每一個執行緒有一個工作記憶體區,其中保留了它必須使用或賦值的變數的一個自己的工作拷貝。當執行緒執行時,它在這些工作記憶體區的拷貝上操作。主記憶體中包含的是每個變數的主拷貝,當允許執行緒(或執行緒需要,如讀)把它的工作拷貝中的內容寫回主記憶體中(或者反之)時,是有一些規則對此加以限制的,這些規則在後面會提到。
一個執行緒可以執行的動作有使用(use)、賦值(assing)、裝載(load)、儲存(store)、鎖定(lock)、解鎖(unlock),而主記憶體可以執行的動作有read、write、lock、unlock,每一個這樣的動作都是原子的。下面是JMM記憶體模式圖:
使用(use)和賦值(assing)操作是執行緒的執行引擎(為上圖中的Thread Execution Engine)和執行緒的工作記憶體(為上圖中的Working Memory)之間緊密藕合(直接,即一步就可以完成的)的互動過程;鎖定(lock)和解鎖(unlock)操作是執行緒的執行引擎和主記憶體之間緊密藕合的互動過程;但在主記憶體和執行緒的工作記憶體間的資料傳送是鬆散藕合的,當資料從主記憶體複製到工作儲存時,必須出現兩個動作:由主記憶體執行的讀(read)動作,一段時間後是由工作記憶體執行的相應的load動作;當資料從工作記憶體拷貝到主記憶體時,必須出現兩種動作:由工作記憶體執行的儲存(store)動作,一段時間後是由主記憶體執行的相應的寫(write)動作。在主記憶體和工作記憶體間傳送資料需一定的傳送時間,而且對每次的傳送的傳送時間可能是不同的:因此在另一個執行緒看來,執行緒對不同變數所執行的動作可能是按照不同的順序(與程式程式碼語義順序)執行的(比如說,執行緒內的程式程式碼是先給變數a賦值,再給變數b賦值,而在另一執行緒看來有可能先看見主記憶體中的b變數更新,再看見a變數更新),然而,任何一個執行緒在主記憶體中對一個變數的所有動作一定是按照這個執行緒中所有對該變數動作的相同次(也是指與程式程式碼語議的順序)序執行。
每種操作的詳細定義:
- 執行緒的use動作把一個變數的執行緒工作拷貝的內容傳送給執行緒執行引擎。每當執行緒執行一個用到變數的值的虛擬機器指令時執行這個動作。
- 執行緒的assign動作把一個值從執行緒執行引擎傳送到變數的執行緒工作拷貝。每當執行緒執行一個給變數賦值的虛擬機器指令時執行這個動作。
- 主記憶體的read動作把一個變數的主記憶體拷貝的內容傳輸到執行緒的工作記憶體以便後面的load動作使用。
- 執行緒的load動作把read動作從主記憶體中得到的值放入變數的執行緒工作拷貝中。
- 執行緒的store動作把一個變數的執行緒工作拷貝內容傳送到主記憶體中以便後面的write動作使用。
- 主記憶體的write動作把store動作從執行緒工作記憶體中得到的值放入主記憶體中一個變數的主拷貝。
- 和主記憶體緊密同步的執行緒的lock動作使執行緒獲得一個獨佔鎖定的宣告。
- 和主記憶體緊密同步的執行緒的unlock動作使執行緒釋放一個獨佔鎖定的宣告。
這樣,執行緒和變數的相互作用由use、assign、load和store動作的序列組成。主記憶體為每個load動作執行read動作,為每個Store動作執行write動作。執行緒的鎖定的相互作用由lock或unlock動作順序組成。
執行緒的每個load動作有唯一一個主記憶體的read動作和它相匹配,這個load動作跟在read動作的後面;執行緒的每個store動作有唯一一個主記憶體的write動作和它相匹配,這個write動作跟在store動作的後面。
變數規則:不允許一個執行緒丟棄它的最近的assign操作;不允許一個執行緒無原因地把資料從執行緒的工作記憶體寫回到主記憶體中;一個新的變數只能在主記憶體中產生並且不能在任何執行緒的工作記憶體中初始化。
假設動作A是執行緒T對變數V執行的另外的load或store動作,假設動作P是主記憶體對變數V執行的相應的read或write動作。類似地,假設動作B是執行緒T對同一個變數V執行的另外的load或store動作,假設動作Q是主記憶體對變數V執行的相應的read或write動作。如果A等於B,那麼必須有P先於Q。(不很嚴格地:為了一個執行緒,主記憶體執行對給定的一個變數的主拷貝動作必須遵循執行緒執行時要求的先後順序。)注意,這條規則只適用於一個執行緒對於同一個變數不同動作的情況,是針對單執行緒提出的。然而,對於volatile 型別的變數有更嚴格的規則,請看後面volatile變數規則最後一條。
double和long型別變數的非原子處理:如果一個double或者long變數沒有宣告為volatile ,則變數的read或write動作,實際在主記憶體處理時是把它當作兩個32位的read或write動作,這兩個動作在時間上是分開的,可能會有其它的動作介於它們之間。這樣的結果是,如果兩個併發的執行緒對共享的非volatile 型別的double或long變數賦不同的值,那麼隨後對該變數的使用而獲取的值可能不等於任何一個執行緒所賦的值,而可能是依賴於具體應用的兩個執行緒所賦的值的混合。基於目前32晶片技術,在共享double和long變數時必須同步。
在一個時刻,對同一個鎖,只能有一個執行緒擁有它,而且一個執行緒可以對同一個鎖執行多次lock動作,只有當對這個鎖執行相同次數的unlock動作後,執行緒才會釋放該鎖定。
一個執行緒如果沒有擁有鎖,那麼它不允許對該鎖實施unlock動作。
如果一個執行緒對任何一個鎖定實施unlock,執行緒必須先把它工作記憶體中的賦的值寫回到主記憶體中(即unlock動作會引發對變數的store -> write -> unlock 動作序列)。
一個lock動作發生時會清空執行緒工作記憶體中所有變數,所以在使用它們的時候必須從主記憶體中載入或重新賦值(即lock動作會引發對變數的lock -> read -> load 或lock -> assign -> store動作序列)。
volatile 型別變數的規則:如果一個變數宣告為volatile 型別,那麼每個執行緒對該變數實施的動作有以下附加的規則,假定T表示一個執行緒,V,W表示volatile 型別變數:
- 只有當執行緒T對變數V執行的前一個動作是load的時候,執行緒T才能對變數V執行use動作;並且,只有當執行緒T對變數V執行的後一個動作是use的時候,執行緒T才能對變數V執行load動作。執行緒T對就是V的use動作可以認為是和執行緒T對變數V的load動作相應的read動作相關聯(這樣可以保證看其他執行緒對變數V所做的修改後的值,即使用時先去從主記憶體中載入)。
- 只有當執行緒T對變數V執行的前一個動作是assign的時候,執行緒T才能對變數V執行store動作;並且,只有當執行緒T對變數V執行的後一個動作是store的時候,執行緒T才能對變數V執行assign動作。執行緒T對就是V的assign動作可以認為是和執行緒T對變數V的store動作相應的write動作相關聯(這樣可以保證其他執行緒可以看到自己對變數V所做的修改,即修改後寫回主記憶體中)。
- 假定動作A是執行緒T對變數V實施的use或assign動作,假定動作F是和動作A相關聯的load或store動作,假定動作P是和動作F相應的對變數V的read或write動作;類似的,假定動作B是執行緒T對變數W實施的use或assign動作,假定動作G是和動作B相關聯的load或store動作,假定動作Q是和動作G相應的對變數W的read或write動作。如果A先於B,那麼P先於Q(不嚴格地:為了一個執行緒T,主記憶體實施對給定的volatile變數的主拷貝的動作必須遵循和執行緒執行時要求的一樣的先後順序。也即將V,W變數寫回到主記憶體的順序與程式程式碼行對V,W賦值先後順序一樣;執行緒將V,W變數從主記憶體讀取出來的順序與程式程式碼行對V,W使用先後順序一樣。即volate禁止了變數間的重新排序問題)。該規則進一步加強了多執行緒訪問共享變數的安全性,這條規則是針對多執行緒提出的。
對宣告為volatile 的變數的規則有效地保證了:執行緒對一個宣告為volatile 的變數的每個use或assign動作只要訪問主記憶體一次,並且依照執行緒的執行語義所指定的次序訪問主記憶體,然而,對沒有宣告為volatile 的變數的read或write動作,這樣的記憶體動作是沒有次序限制的。
volatile 的變數除了具有可見性外,還禁止了多個變數間的Reordering。
範例:可能的交換
Java程式碼- class Sample{
- int a=1,b=2;
- void hither(){
- a=b;
- }
- void yon(){
- b=a;
- }
- }
讓我們考慮呼叫hither的執行緒,按照規則,該執行緒必須執行變數b的use動作,在它後面要執行變數a的assign動作,這是對hither的最低要求(即同一執行緒內一定是按照程式語義順序來執行)。
現線上程對變數b的第一個動作不能為use,但是可以為assign或load。這裡對b的一個assign動作不可能發生,因為這裡根本就沒有賦值呼叫,所以這裡只有對變數b的load動作。而執行緒對這個load動作必須有一個更早的主內豐對變數b的read動作。
在對變數a進行assign動作後,執行緒可選地(因為沒有使用同步)儲存變數a的值,如果執行緒要儲存這個值,那麼執行緒實施store動作,並且主記憶體接著實施變數a的write動作。
呼叫方法yon的執行緒的情況是類似的,只是a和b交換了各自的角色。所有的動作序列可以由下面圖描述,執行時可能會從這些任意的箭頭中切換到另一執行緒執行:
假定ha和hb是呼叫hither的執行緒的變數a和b的工作拷貝,假定ya和yb是呼叫yon執行緒的變數a和b的工作拷貝,假定ma和mb是主記憶體中變數a和變數b的主拷貝,假定初始化ma=1,mb=2,下面是動作的可能結果:
1、 ha=2,hb=2,ya=2,yb=2,ma=2,mb=2(結果是b拷貝給了a)
2、 ha=1,hb=1,ya=1,yb=1,ma=1,mb=1(結果是a拷貝給了b)
3、 ha=2,hb=2,ya=1,yb=1,ma=2,mb=1(結果是a、b交換了)
使用以下程式進行測試:
- class Sample {
- /*
- * 不管 a,b是否使用volatile 修飾,都會出現 a、b值交換。因為a=b、b=a並不是原子性
- * 的,因為這兩條語句都會涉及到使用與賦值兩個動作,完全有可能在訪問操作後切換到
- * 另一執行緒,而volatile並不像synchronized那樣具有原子特性
- */
- volatile int a = 1;
- volatile int b = 2;
- void hither() {
- a = b;
- }
- synchronized void yon() {
- b = a;
- }
- }
- public class Test {
- public static void main(String[] args) throws Exception {
- while (!Thread.currentThread().isInterrupted()) {
- final Sample s = new Sample();
- final Thread hither = new Thread() {
- public void run() {
- s.hither();
- }
- };
- final Thread yon = new Thread() {
- public void run() {
- s.yon();
- }
- };
- hither.start();
- yon.start();
- new Thread() {
- public void run() {
- try {
- hither.join();
- yon.join();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- if (s.a != s.b) {
- // 某次列印結果Thread-332984: a=2 b=1
- System.out.println(this.getName() + ": a=" + s.a + " b=" + s.b);
- System.exit(0);
- }
- }
- }.start();
- Thread.yield();
- }
- }
- }
上面使用volatile 同時修改這兩個變數還是不行的,除非兩個方法同時(注,只一個方法使用也是不管用的)使用synchronized:
Java程式碼- class Sample {
- int a = 1;
- int b = 2;
- synchronized void hither() {
- a = b;
- }
- synchronized void yon() {
- b = a;
- }
- }
lock和unlock動作對主記憶體的動作次序提出了更多的限制。在一個執行緒的lock動作和unlock動作之間,另一個執行緒不能實 施lock動作,而且,unlock動作前需要實施store動作和write動作,下面是僅可能發現的順序,從結果看出要麼是a,要麼 是b,不可能出現兩都交換的情況:
1、 ha=2,hb=2,ya=2,yb=2,ma=2,mb=2(結果是b拷貝給了a)
2、 ha=1,hb=1,ya=1,yb=1,ma=1,mb=1(結果是a拷貝給了b)
範例:無序寫入
下面的例子和前面的例子很相似,只是一個方法對兩個變數賦值,而中一個方法讀取兩個變數的值:
- class Sample {
- int a = 1;
- int b = 2;
- String result;
- synchronized void to() {
- a = 3;
- b = 4;
- }
- void fro() {
- // 按理來說不可能出現 a=1,b=4
- result = "a=" + a + ",b=" + b;
- }
- }
從上圖可以看出,線上程內:呼叫方法to的執行緒在方法結束而實施unlock動作前,必須實施stroe動作將所賦的值寫回到主記憶體中。呼叫方法fro的執行緒必須同樣的次序使用變數a和b(即先use a再use b),並且必須從主記憶體對變數a和b實施load動作以將值裝入a和b。
在主記憶體中:動作發生的次序是這樣的呢?注意規則並不要求對變數a的write動作要先於對變數b的write動作;而且也不要求對變數a的read動作要先於對變數b的read動作。甚至由於方法to是同步的,方法fro沒有同步,所以不能防止在lock動作和unlock動作間發生read動作(即,宣告一個方法為同步的,這種機制本身不能使方法的行為是原子的)。
上面結果輸出有可能是a=1,b=4,這說明儘管一個執行緒對變數a的assign動作先於變數b的assign動作,在另一個執行緒看來,主記憶體實施可能是按照相反的次序實施相應的write動作,但如果是volatile變數,則會以程式語義執行的順序寫回主記憶體。
什麼是重新排序?
在一些情況下,對程式變數(物件例項變數、靜態變數、陣列元素)進行訪問的時候,會發現訪問的執行順序與程式中所指定的順序並不一致。只要不改變程式的語義,編譯器為了進行程式的優化可以自由地reorder指令(instructions)。處理器也可能以不同的順序去執行指令:資料可能會以不同於程式中所指定的順序在處理器暫存器、處理器快取以及住記憶體之間移動。
在單執行緒的情況下,程式不必去關注指令的真實執行順序,同時也不必在意reordering的影響。然而,在多執行緒的情況下,如果程式沒有被正確地synchronized,執行緒就會受到reordering的影響,即一個執行緒可能會看到另一個執行緒對變數訪問過程的次序與程式中指定的次序不同的結果。例如,如果一個執行緒先寫入a欄位,然後再寫入b欄位,如果b的值不依賴於a的值,則編譯器可以自由地recorder這些操作,而且可以將快取中b的值先寫回到主記憶體中再寫回a,這樣另一執行緒會先看到b,最後該執行緒看到的結果與程式中指定的次序不同。
可能進行reorder的地方包括:編譯器、JIT、處理器快取。
JMM 允許編譯器和快取以資料在處理器特定的快取(或暫存器)和主存之間移動的次序擁有重要的特權,除非程式設計師已經使用 synchronized 或 final 明確地請求了某些可見性保證。這意味著在缺乏同步的情況下,從不同的執行緒角度來看,記憶體的操作是以不同的次序發生的。
例子:
Java程式碼- Class Reordering {
- int x = 0, y = 0;
- public void writer() {
- x = 1;
- y = 2;
- }
- public void reader() {
- int r1 = y;
- int r2 = x;
- }
- }
假設有兩個執行緒分別執行上面的示例程式程式碼中的writer和reader方法。在writer方法的程式中,x被指定在y之前進行賦值。但是由於對y的賦值並不依賴於x的值,因此編譯器可以reorder這些操作。另外,執行writer執行緒的處理器也完全可以先將cache中y的值寫回記憶體,然後再將x的值寫回記憶體。在兩個操作的中間(y的值已經被寫回記憶體,但是x的值尚未被寫回記憶體的時候),執行reader方法的執行緒得到的結果便是 r1 = 2,但是 r2 = 0,而不是x的真實值1。
Volatile關鍵字規則:
volatile欄位被用來線上程之間communicate state(交流規則)。任意執行緒所read的volatile欄位的值都是最新的。原因有以下有4點:
(1) 編譯器和JVM會阻止將volatile欄位的值放入處理器暫存器(register);
(2) 在write volatile欄位之後,其值會被flush出處理器cache,寫回memory;
(3) 在read volatile欄位之前,會invalidate(驗證)處理器cache。
因此,上述兩條便保證了每次read的值都是從memory中的,即具有“可見性”這一特性。
(4) 禁止reorder(重排序,即與原程式指定的順序不一致)任意兩個volatile變數,並且同時嚴格限制(儘管沒有禁止)reorder volatile變數周圍的非volatile變數。這一點即volatile具有變數的“順序性”,即指令不會重新排序,而是按照程式指定的順序執行。
注:在舊的記憶體模型下,對volatile修改的變數的訪問順序不能進行重新排序,但可以對非volatile變數進行排序,但這樣又可能還是會導致volatile變數可見性問題,所以老的舊記憶體模型沒有從根本上解決volatile 變數的可見性問題。在新的記憶體模型下,仍然是不允許對volatile變數進行reorder的,不同的是再也不輕易(雖然沒有完全禁止掉)允許對它周圍的非volatile變數進行排序。
由於第(4)條中對volatile欄位以及周圍非volatile欄位(或變數)reorder的限制,如下程式中,假設執行緒A 正在執行reader方法,同時,執行緒B正在執行writer方法。執行緒B完成對volatile欄位 v 的賦值後,相應的結果被寫回記憶體。如果此時執行緒 A 便得到的 v 的值正好為true,那麼執行緒A也可以安全地引用 x 的值。然而,需要注意的是,假如v不是volatile的,那麼上述結果就不一定了,因為x和v賦值的順序可能被reorder。
- class VolatileSample1 {
- int x = 0;
- volatile boolean v = false;
- public void writer() {
-
相關推薦
Java記憶體模型與volatile
記憶體模型描述的是程式中各變數(例項域、靜態域和陣列元素)之間的關係,以及在實際計算機系統中將變數儲存到記憶體和從記憶體取出變數這樣的低層細節。 每一個執行緒有一塊工作記憶體區,其中保留了被所有執行緒共享的主記憶體中的變數的值的拷貝。為了存取一個共享的變數,一個執行緒通常先獲取鎖定並且清除它
java的記憶體模型與volatile關鍵字詳解
由於各種硬體及作業系統的記憶體訪問差異,java虛擬機器使用java記憶體模型(java Memory Model,JMM)來規範java對記憶體的訪問。這套模型在jdk 1.2中開始建立,經jdk 1.5的修訂,現已逐步完善起來。 什麼是java記憶體模
多執行緒讀書筆記二(java記憶體模型、volatile變數、記憶體模型與synchronized、CAS)
java記憶體模型 java中,執行緒之間的通訊是通過共享記憶體的方式,儲存在堆中的例項域,靜態域以及陣列元素都可以線上程間通訊。java記憶體模型控制一個執行緒對共享變數的改變何時對另一個執行緒可見。 執行緒間的共享變數存在主記憶體中,而對於每一個執行緒,都有一個私有的工
十一、JVM(HotSpot)Java記憶體模型與執行緒
注:本博文主要是基於JDK1.7會適當加入1.8內容。 1、Java記憶體模型 記憶體模型:在特定的操作協議下,對特定的記憶體或快取記憶體進行讀寫訪問的抽象過程。不同的物理機擁有不一樣的記憶體模型,而Java虛擬機器也擁有自己的記憶體模型。 主要目標:定義程式中各個變數的訪問規則,
從Java記憶體模型解析volatile關鍵字
面試裡面多執行緒是繞不開的話題,補習多執行緒的時候看到一篇好文章,從Java記憶體模型的角度解析volatile關鍵字,對於多執行緒新手的我來說收穫很多。 原文連結: http://www.cnblogs.com/dolphin0520/p/3920373.html
Java記憶體模型與執行緒知識點總結
首先討論一下物理機對於併發的處理方案 運算任務不可能只靠處理器簡單的計算就能完成,必須還要增加與記憶體的互動操作(如讀取資料,儲存資料), 由於計算機的儲存裝置與處理器的運算速度之間有著幾個數量級的差距,所以現代計算機系統選擇加入快取記憶體(Cache)來進行記憶體與處理器之間的快取來提高效率 由於快取記
Java記憶體模型與執行緒——Java記憶體模型
文章目錄 一、主記憶體與工作記憶體 1.1 Java記憶體模型中的變數 1.2 主記憶體與工作記憶體 二、主記憶體與工作記憶體間互動操作 三、對於volatile型變數的特殊規則 3.1 可見性 3.2
Java記憶體模型與執行緒——硬體的效率與一致性,記憶體模型
文章目錄 一、先來一個問題,想要電腦快,買記憶體條還是固態硬碟? 二、衡量一個服務效能好壞的標準之一 三、硬體的效率與一致性 3.1 硬體的效率與一致性問題是怎樣出來的? 四、記憶體模型 一、先來一個問題
深入理解Java虛擬機器筆記——Java記憶體模型與併發程式設計
當程式在執行過程中,會將運算需要的資料從主存複製一份到CPU的快取記憶體中,那麼CPU進行計算時就可以直接從它的快取記憶體讀取資料和向其中寫入資料,當運算結束後,再將告訴快取中的資料重新整理到主存中。 如果一個變數在多個CPU中都存在快取,那麼就存在快取一致性
Java記憶體模型與執行緒 深入理解Java虛擬機器總結
在許多情況下,讓計算機同時去做幾件事情,不僅是因為計算機的運算能力強大了,還有一個很重要的原因是計算機的運算速度與它的儲存和通訊子系統速度的差距太大, 大量的時間都花費在磁碟I/O、網路通訊或者資料庫訪問上。 如果不希望處理器在大部分時間裡都處於等待其他資源的狀態,就必須使用一些手段去把處理器
1.java一切即物件以及java記憶體模型與執行緒
由此可以得知: 程式碼完成之後進行本地配置的一些讀取操作: 至此可以得知其編譯模式是mixed模式的 new date()預設輸出的結果是import中包的預設建構函式初始化後的結果: 觀看Date類原始碼即可得知: 鑑於java是單繼承關係,由此來看一下imp
讀書筆記 ---- 《深入理解Java虛擬機器》---- 第11篇:Java記憶體模型與執行緒
上一篇:晚期(執行期)優化:https://blog.csdn.net/pcwl1206/article/details/84642835 目 錄: 1 概述 2 Java記憶體模型 2.1 主記憶體與工作記憶體 2.2
【Java虛擬機器】Java記憶體模型與執行緒
Java記憶體模型與執行緒 Java記憶體模型 記憶體間互動操作 volatile關鍵字 Java與執行緒 核心實現 使用使用者執行緒實現 使用使用者執行緒加輕量級程序混合實現 Java執行緒的實現
深入理解JVM(十一)——Java記憶體模型與執行緒
計算機運算的速度,與它的儲存和通訊子系統相差太大,大量的時間花費在磁碟IO,網路通訊和資料庫上。 衡量一個服務效能的高低好壞,每秒事務處理數TPS是最重要的指標。 對於計算量相同的任務,程式執行緒併發協調的越有條不紊,效率越高;反之,執行緒之間頻繁阻塞或是死鎖,將大大降低併發能力。
深入理解 Java 虛擬機器(十二)Java 記憶體模型與執行緒
執行緒安全 Java 語言中的執行緒安全 根據執行緒安全的強度排序,Java 語言中各種操作共享的資料可以分為 5 類:不可變、絕對執行緒安全、相對執行緒安全、執行緒相容、執行緒對立。 不可變 不可變的物件一定是執行緒安全的,如果共享資料是一個基本資料型別,那麼
java記憶體模型與執行緒(1)
一、處理器、快取記憶體、主記憶體之前的互動圖 二、Java記憶體模型 倆張圖之間的關係很清晰 一個處理器對應一個執行緒 一個快取記憶體對應一個工作記憶體 問題的關鍵點就在於:java執行緒之間與工作記憶體打交道,而不是主記憶體,工作記憶體之間沒有直接的關
java記憶體模型與執行緒(2)
一、原子性、可見性與有序性 1.原子性 原子性操作包括read、load、asign、use、store和write 更大範圍的原子性保證:lock和unlock(倆者未開放),monitorenter和monitorexit(隱式的使用synchronized)
Java記憶體模型與物件揭祕
看了很多個關於Java記憶體模型的部落格,這篇部落格有著獨到的見解. 前言:最近看了《深入jvm》一書,感受頗深,但是不寫點什麼總感覺不是自己的,所以動手捋一捋。主要講的內容是java的記憶體區域,物件的建立,物件的記憶體佈局和物件的訪問方式。 一、java的記憶體區域劃
深入理解Java虛擬機器讀書筆記8----Java記憶體模型與執行緒
八 Java記憶體模型與執行緒 1 Java記憶體模型 ---主要目標:定義程式中各個變數的訪問規則,即在虛擬機器中將變數儲存到記憶體和從記憶體中取出變數這樣的底層細節。 ---此處的變數和Java中的變
jdk原始碼解析(十一)——Java記憶體模型與執行緒
前面我們瞭解了Java的編譯和執行,這裡在講解一下高效併發(Java記憶體模型與執行緒)在瞭解記憶體模型與執行緒之前,我們先要了解一些東西。 1 硬體效率與一致性 計算併發執行的執行和充分利用計算機處理器的效能兩者看來是互為因果的,而在大多數的時候,計算機的處理速度不止是在處理器