三天沒有寫博客了,三天都在整理併發編程的知識,發覺真的太多了,放到一起肯定不好整理,就這樣分開整理,方便自己平時的閱讀!
併發關鍵字:
-
volitile
- 特性:
可見性
:在變量前面加了volatile的關鍵字就是指示JVM
這個變量不穩定
,所有線程更新它時都會立即同步到主存
中,所有線程使用它的時候都會到主存中讀取
,這樣保證了所有的線程使用該變量時都是最新的
。原理
:volatile是從JVM
層面保證變量的可見性
。JVM中所有的變量存儲在主內存
中,同時每個線程又有自己獨立的緩存
用來存儲從主內存中緩存的數據,這樣每次獲取更新數據時更新緩存中的數據,然後再同步到主存中,這樣就減輕了主存的壓力,而volatile怎麼解決的可見性問題呢?首先爲了維持緩存以及主從中數據一致性的問題,volatile使用了JVM層面中的lock
鎖,當一個volatile的變量更新時,會對該線程進行lock加鎖,同時也會讓其它線程中緩存的該變量都失效
,當執行成功之後將該變量寫入
主內存中,然後解除lock
狀態,這樣每次一個更新操作都是立即同步
到主存中的,而所有的讀取變量也都是通過該操作獲取到主存中最新的值。
禁止重排序
:對於使用volatile關鍵字的變量來說,volatile能夠保證它前面的操作都已經執行完畢並且返回的結果對後面的操作可見,後面的操作還沒有執行,能夠按照設定的順序執行一系列操作
。-
原理
:volatile也是從JVM
層面也保證有序性
的。在程序中有很多的優化重排序:編譯器優化的重排序
、指令級的優化重排序
、內存系統的優化重排序
,而volatile爲了解決防止這些重排序的發生,使用了內存屏障
來解決排序問題,也就是在每個volatile操作的前後都加入一個內存屏障,來保證前後的執行都是按照順序執行的,實現如下:- 在每個volatile寫操作的前面插入一個
StoreStore
的屏障,同時在volatile寫操作的後面插入一個StoreLoad
的屏障, - 在每個volatile讀操作的前面加入
LoadLoad
屏障同時在每個volatile讀操作後面加入LoadStore
屏障
通過設定這樣的內存屏障來保證操作都是按照順序來執行的。
- 在每個volatile寫操作的前面插入一個
-
- 用法:使用在
變量
中
- 特性:
-
synchronized
- 特性:
- **
原子性:
**一個或多個操作要麼全部執行成功要麼全部執行失敗。 - **
有序性:
**線程的執行順序按照設定的順序執行。 - **
可見性:
**一個線程對變量的修改其它線程能立即看到改變的值 - **
可重入性:
**同一個線程可以獲取同一把鎖多次(wait、notify、notifyAll的作用
)
- **
- 用法:
-
實例方法
:在普通方法中使用synchronized
關鍵字,作用的是實例對象
。 synchronized都是作用在對象中的,只有作用在對象中,才能使用wait
、notify
、notifyAll
來重新執行該線程。在實例方法中是通過ACC_SYNCHRONIZED
這樣一個標誌,來告訴JVM
這是一個同步方法
,因此在進入該方法之前先要獲取相應的鎖
,然後鎖的計數器+1
,執行結束後計數器-1
,如果失敗就阻塞,直到該鎖被釋放,因此synchronized關鍵字作用於方法是都是通過ACC_SYNCHRONIZED
來實現一個加鎖的操作的。 -
靜態方法
:在靜態方法中使用synchronized
關鍵字,作用的是整個類對象
。此時也是作用於方法中的,所以也是通過ACC_SYNCHRONIZED
來實現的加鎖操作。 -
代碼塊
:在代碼塊中使用synchronized關鍵字,作用的是調用這個代碼塊的對象
。在代碼塊中由monitorenter
指令進入,然後monitorexit
釋放鎖,在執行monitorenter之前需要嘗試
獲取鎖,如果這個對象沒有被鎖定,或者當前線程已經擁有了這個對象的鎖,那麼就把鎖的計數器加1
。當執行monitorexit指令時,鎖的計數器也會減1
。當獲取鎖失敗時會被阻塞,一直等待鎖被釋放。
但是反編譯的代碼中有兩個
monitorexit,這是因爲第二個monitorexit是來處理異常
的,正常情況下第一個monitorexit之後會執行goto指令,而該指令轉向的就是末尾的return,也就是說正常情況下只會執行第一個monitorexit釋放鎖,然後返回。而如果在執行中發生了異常,第二個monitorexit就起作用了,它是由編譯器自動生成的,在發生異常時處理異常然後釋放掉鎖。 -
**
總結:
**在JVM中,對象是分成三部分存在的:對象頭
、實例數據
、對齊填充
。- 對象頭:要結構是由Mark Word 和 Class Metadata Address 組成,其中Mark Word存儲對象的hashCode、鎖信息或分代年齡或GC標誌等信息,Class Metadata Address是類型指針指向對象的類元數據,JVM通過該指針確定該對象是哪個類的實例
- 實例數據:存放類的屬性數據信息,包括父類的屬性信息,如果是數組的實例部分還包括數組的長度
- 對齊填充:部分內存按4字節對齊;對其填充不是必須部分,由於虛擬機要求對象起始地址必須是8字節的整數倍,對齊填充僅僅是爲了使字節對齊
synchronized作用的是對象
,這也是爲什麼等待和通知是在Object類中而不是在Thread中聲明的
一個原因。
-
- 特性:
今天依然是會敲代碼的湯姆貓!