java代碼在編譯后會(huì)變成Java字節(jié)碼, 字節(jié)碼被ClassLoader加載到JVM中, JVM執(zhí)行字節(jié)碼, 最終要轉(zhuǎn)化為匯編指令在CPU上執(zhí)行, Java中所使用的并發(fā)機(jī)制依賴于JVM的實(shí)現(xiàn)和CPU的指令.
volatile是輕量級(jí)的synchronized, 它在多CPU(注意不僅僅是多核)開發(fā)中保證了共享變量的可見性.
由于volatile只保證了可見性, 無法保證原子性, 所以比synchronized的執(zhí)行成本更低, 它不會(huì)引起上下文的切換和調(diào)度.
為加快CPU的處理速度, 它是不直接與內(nèi)存進(jìn)行通信, 而是先將系統(tǒng)內(nèi)存的數(shù)據(jù)讀到CPU內(nèi)部緩存(L1, L2或其他)后再進(jìn)行操作, 但操作完全不知道何時(shí)會(huì)寫回內(nèi)存.
被volatile標(biāo)注的變量如果被修改了, 會(huì)引起一系列的變化:
Java中的每一個(gè)對象都可以作為鎖
JavaSE 1.6中, 鎖一共有四種狀態(tài), 級(jí)別從低到高依次為: 無鎖狀態(tài), 偏向鎖, 輕量級(jí)鎖, 重量級(jí)鎖. 當(dāng)?shù)图?jí)的鎖機(jī)制不適配的時(shí)候, 程序會(huì)自動(dòng)將鎖升級(jí)為高級(jí)別的鎖.
偏向鎖使用了一種等到競爭出現(xiàn)才釋放鎖的機(jī)制, 所以當(dāng)其他線程嘗試競爭偏向鎖時(shí), 持有偏向鎖的線程才會(huì)釋放鎖.
在競爭鎖的時(shí)候, 不會(huì)阻塞, 而是使用’自旋’機(jī)制反復(fù)嘗試獲取鎖(始終消耗CPU時(shí)間片), 直到獲取鎖.
就是JavaSE 1.6之前的鎖機(jī)制
| 類別 | 優(yōu)點(diǎn) | 缺點(diǎn) | 適用場景 |
|---|---|---|---|
| 偏向鎖 | 和執(zhí)行非同步的方法相比僅存在納秒級(jí)的差距 | 如果線程間存在鎖競爭, 則會(huì)帶來額外的鎖撤銷的消耗 | 適用于長期只有一個(gè)線程訪問同步塊的場景 |
| 輕量級(jí)鎖 | 競爭鎖的線程不會(huì)阻塞, 提高了程序的響應(yīng)速度 | 競爭的線程會(huì)自旋, 消耗CPU | 追求響應(yīng)時(shí)間, 且同步塊執(zhí)行速度非常快的場景 |
| 重量級(jí)鎖 | 競爭鎖的線程不自旋, 不會(huì)消耗CPU | 競爭鎖的線程會(huì)阻塞, 相應(yīng)時(shí)間緩慢 | 追求吞吐量, 或者是同步塊執(zhí)行時(shí)間較長的時(shí)候 |
原子操作的定義是:
不可被中斷的一個(gè)或者一系列操作
使用處理器提供的一個(gè)LOCK#信號(hào), 當(dāng)一個(gè)處理器在總線上輸出此信號(hào)時(shí), 其他處理器的請求將被阻塞, 那么該處理器可以獨(dú)占共享內(nèi)存.
同一時(shí)刻, 我們只需要保證對某個(gè)內(nèi)存地址的操作是原子性的即可
Java中可以通過鎖和循環(huán)CAS(Compare and Set)的方式來實(shí)現(xiàn)原子操作, 具體的表現(xiàn)形式是內(nèi)置了一些類來支持原子操作: 如AtomicBoolean, AtomicInteger, AtomicLong等
循環(huán)開銷大:
自旋CAS如果長時(shí)間不成功, 會(huì)給CPU帶來非常大的執(zhí)行開銷
只能保證一個(gè)共享變量的原子操作
如果一個(gè)類有兩個(gè)以上的field時(shí), 就需要使用鎖了.
實(shí)際上線程操作鎖的方式在底層也是使用循環(huán)CAS的方式來進(jìn)行鎖的獲取和釋放的.
新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注