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