Synchronized和CAS

什麼是CAS?

CAS的全稱是 Compare And Swap(Compare And Exchange) 比較並交換,

cas(v,a,b) 變量v,期待值a, 修改值b

CAS底層通過Lock指令實現。

以 java.util.concurrent.atomic包下的 AtomicInteger 爲例

調用的unsafe.getAndAddInt

getAndAddInt 是一個do..while死循環調用compareAndSwapInt方法

compareAndSwapInt 是一個native方法

jdk8u: unsafe.cpp:

UNSAFE_ENTRY(jboolean, Unsafe_CompareAndSwapInt(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jint e, jint x))
  UnsafeWrapper("Unsafe_CompareAndSwapInt");
  oop p = JNIHandles::resolve(obj);
  jint* addr = (jint *) index_oop_from_field_offset_long(p, offset);
  return (jint)(Atomic::cmpxchg(x, addr, e)) == e;
UNSAFE_END

jdk8u: atomic_linux_x86.inline.hpp 

inline jint     Atomic::cmpxchg    (jint     exchange_value, volatile jint*     dest, jint     compare_value) {
  int mp = os::is_MP();
  __asm__ volatile (LOCK_IF_MP(%4) "cmpxchgl %1,(%3)"
                    : "=a" (exchange_value)
                    : "r" (exchange_value), "a" (compare_value), "r" (dest), "r" (mp)
                    : "cc", "memory");
  return exchange_value;
}

最終是通過LOCK_IF_MP 實現。

CAS的ABA問題

什麼是aba問題,打個比方, 要修改的變量a的值原本是1,被另一個線程改成了2之後又改成了1,這個時候1還是1,但它已經被修改過了。
舉個例子:你的女朋友在和你分開後經歷了別的男人又回到你身邊怎麼辦?當然是選擇原諒她

解決方法,加版本號,AtomicStampedReference類

CAS是 樂觀鎖 / 自旋鎖 / 輕量級鎖 ,之前的synchronized是重量級鎖,現在有鎖升級過程。

Synchronized

synchronized鎖的是對象而不是代碼,通過對象頭上的兩位控制是不是加了鎖,加了什麼類型的鎖。

64位hotspot的實現爲

001 表示 無鎖態
101 表示偏向鎖
00   表示輕量級鎖
10   表示重量級鎖
11   GC回收標誌

鎖升級過程

1、對象剛創建時是 無鎖 或者 匿名偏向鎖
匿名偏向:如果偏向鎖打開了就是匿名偏向鎖,沒打開就是無鎖,匿名偏向鎖在JVM啓動4秒後打開,延遲4秒是因爲JVM啓動的時候就已經知道哪些對象有競爭,就直接設置爲輕量級鎖,如果設置成匿名偏向鎖還要撤銷鎖升級成輕量級鎖,消耗資源。

2、如果有線程上鎖,上偏向鎖,偏向鎖就是把markword的線程ID改爲自己線程ID,下次同一個線程加鎖的時候,不需要爭用,只需要判斷下線程指針是否是同一個,所以,偏向鎖,偏向加鎖的第一個線程。hashcode備份在線程棧上,線程銷燬,鎖降級成無鎖

3、如果有線程競爭撤銷偏向鎖升級爲輕量級鎖自旋鎖),每個線程都有自己的LockRecord在自己的線程棧上,用CAS去爭用加鎖對象markword的LR的指針,指針指向哪個線程的LR,哪個線程就擁有鎖。

4、如果競爭加劇,升級重量級鎖,向操作系統申請資源,線程掛起,進入等待隊列,等待操作系統的調度。
競爭加劇:JDK1.6之前自旋10次或者自旋線程數超過CPU核心數一般升級重量級鎖,JDK1.6加入自適應自旋,由JVM自己控制。

CAS和Synchronized的對比

CAS底層通過LOCK_IF_MP指令實現,在用戶態執行,不用經過操作系統老大,效率高。但死循環消耗CPU,所以CAS適合線程低競爭,低耗時的場景。
synchronized升級爲重量級鎖後線程交給操作系統老大,效率低,但是加入等待隊列後不消耗CPU,所以適合高競爭,高耗時的場景。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章