引入
-
在Java中實作并發很多時候我們都是使用
synchronized關鍵字,自從jdk1.6對synchronized進行重大優化后,其性能問題得到了改善,與ReentrankLock相比性能方面相差無幾 -
性能的改善得益于偏向鎖、輕量級鎖的引入,它們具體的實作方式可參考《Java并發編程的藝術》和《深入理解Java虛擬機》這兩本書,偏向鎖、輕量級鎖和重量級鎖不同的地方在于不是通過信號量機制(強制阻塞)而是通過自旋CAS實作互斥訪問的,避免了強制阻塞時用戶態與核心態之間切換帶來的開銷(系統呼叫),這里的開銷主要是保存用戶態的背景關系資訊,
自旋CAS
-
CAS操作是一個原子操作,所謂原子操作就是指在執行期間不會被其他執行緒打斷,要么執行完畢,要么不執行
-
CAS操作有三個運算元V(記憶體地址),A(舊的預期值),B(準備設定的新值),指令執行時先看V指向的記憶體中存盤的值是否和A相同,如果相同才會更新為B,否則什么也不做,
-
自旋是指當物件或同步塊已經被其他執行緒鎖定時,競爭執行緒空轉等待占用執行緒執行完畢的情形,注意此時競爭執行緒并沒有阻塞,而是原地空轉,執行一個無限回圈判斷物件是否已解鎖,所以不存在用戶態到核心態的轉換,因而同步效率較高(但會占用CPU時間),
從問題出發理解原子性
-
我一直有個疑惑,CAS的原子性和使用CAS加鎖保證執行緒安全有什么關系?假設有多個執行緒同時在對同一塊記憶體進行CAS操作的話,那不就有可能出問題嗎:兩個執行緒T1,T2同時對同一物件執行CAS操作加鎖,V存盤同一塊記憶體地址,A當然也是同樣舊的預期值,那么這種情況下T1和T2都可以進行更新,那么CAS操作加鎖程序就是無效的,因為CAS操作成功后執行緒就會進入同步塊,此時就會有多個執行緒同時執行同步塊中的代碼······那這不就會使同步塊執行緒不安全了嗎,
-
后來我明白了CAS原子性和執行緒安全的關系,在多個執行緒同時CAS的情況下是不會發生多個執行緒CAS成功的情況的,因為計算機底層實作保證了V指向記憶體的互斥性和立即可見性,可以理解為CAS操作是底層保證的執行緒安全
-
首先說結論,一個執行緒T在CAS操作時,其他執行緒無法訪問V指向的記憶體地址,并且一旦T更新了V指向記憶體中的值,其他所有執行緒的V指向記憶體都變得無效,
-
處理器實作原子操作有兩種做法
-
一是總線鎖,在多CPU 下,當其中一個處理器要對共享記憶體進行操作的時候,在總線上發出一個
LOCK#信號,這個信號使得其他處理器無法通過總線來訪問到共享記憶體中的資料 -
二是快取鎖,如果共享記憶體已經被快取,那么鎖總線沒有意義,快取鎖核心是使用了快取一致性協議,如
MESI協議-
MSEI表示快取行的四種狀態
-
M(Modify)表示共享資料只快取在當前 CPU 快取中, 并且是被修改狀態,也就是快取的資料和主記憶體中的資料不一致 -
E(Exclusive)表示快取的獨占狀態,資料只快取在當前 CPU 快取中,并且沒有被修改 -
S(Shared)表示資料可能被多個 CPU 快取,并且各個快取中的資料和主記憶體資料一致 -
I(Invalid)表示快取已經失效
-
-
在
MESI協議中,每個快取的快取控制器不僅知道自己的 讀寫操作,而且也監聽(snoop)其它 Cache 的讀寫操作 -
CPU在讀資料時,如果快取行狀態是I,則需要從記憶體中讀取,并把快取行狀態置為S;如果不是I,則可以直接讀取快取中的值,但在此之前必須要等待對其他CPU的監聽結果,如果其他CPU也有該資料的快取且狀態是M,則需要等待其把快取更新到記憶體后再讀取
-
CPU可以將狀態為
M/E/S的快取寫入記憶體,其中如果快取行狀態為S,則其他CPU快取了相同資料的快取行會無效化
-
-
-
也就是說不會有多個執行緒同時訪問共享變數,而且共享變數更新是對所有執行緒可見的,所以原子操作是執行緒安全的,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/93431.html
標籤:Java
上一篇:精講RestTemplate第4篇-POST請求方法使用詳解
下一篇:PHP中抽象類和介面的區別
