posts - 12, comments - 8, trackbacks - 0, articles - 5
            BlogJava :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

          [轉(zhuǎn)]CAS原理

          Posted on 2010-11-18 15:16 楊羅羅 閱讀(3140) 評論(1)  編輯  收藏 所屬分類: java.thread

          在JDK 5之前Java語言是靠synchronized關(guān)鍵字保證同步的,這會導(dǎo)致有鎖(后面的章節(jié)還會談到鎖)。

          鎖機制存在以下問題:

          (1)在多線程競爭下,加鎖、釋放鎖會導(dǎo)致比較多的上下文切換和調(diào)度延時,引起性能問題。

          (2)一個線程持有鎖會導(dǎo)致其它所有需要此鎖的線程掛起。

          (3)如果一個優(yōu)先級高的線程等待一個優(yōu)先級低的線程釋放鎖會導(dǎo)致優(yōu)先級倒置,引起性能風(fēng)險。

          volatile是不錯的機制,但是volatile不能保證原子性。因此對于同步最終還是要回到鎖機制上來。

          獨占鎖是一種悲觀鎖,synchronized就是一種獨占鎖,會導(dǎo)致其它所有需要鎖的線程掛起,等待持有鎖的線程釋放鎖。而另一個更加有效的鎖就是樂觀鎖。所謂觀鎖就是,每次不加鎖而是假設(shè)沒有沖突而去完成某項操作,如果因為沖突失敗就重試,直到成功為止。

          CAS 操作

          上面的樂觀鎖用到的機制就是CAS,Compare and Swap。

          CAS有3個操作數(shù),內(nèi)存值V,舊的預(yù)期值A(chǔ),要修改的新值B。當且僅當預(yù)期值A(chǔ)和內(nèi)存值V相同時,將內(nèi)存值V修改為B,否則什么都不做。

          非阻塞算法 (nonblocking algorithms)

          一個線程的失敗或者掛起不應(yīng)該影響其他線程的失敗或掛起的算法。

          現(xiàn)代的CPU提供了特殊的指令,可以自動更新共享數(shù)據(jù),而且能夠檢測到其他線程的干擾,而 compareAndSet() 就用這些代替了鎖定。

          拿出AtomicInteger來研究在沒有鎖的情況下是如何做到數(shù)據(jù)正確性的。

          private volatile int value;

          首先毫無以為,在沒有鎖的機制下可能需要借助volatile原語,保證線程間的數(shù)據(jù)是可見的(共享的)。這樣才獲取變量的值的時候才能直接讀取。

          public final int get() {
                  return value;
              }

          然后來看看++i是怎么做到的。

          public final int incrementAndGet() {
              for (;;) {
                  int current = get();
                  int next = current + 1;
                  if (compareAndSet(current, next))
                      return next;
              }
          }

          在這里采用了CAS操作,每次從內(nèi)存中讀取數(shù)據(jù)然后將此數(shù)據(jù)和+1后的結(jié)果進行CAS操作,如果成功就返回結(jié)果,否則重試直到成功為止。

          而compareAndSet利用JNI來完成CPU指令的操作。

          public final boolean compareAndSet(int expect, int update) {   
              return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
              }

          整體的過程就是這樣子的,利用CPU的CAS指令,同時借助JNI來完成Java的非阻塞算法。其它原子操作都是利用類似的特性完成的。

          而整個J.U.C都是建立在CAS之上的,因此對于synchronized阻塞算法,J.U.C在性能上有了很大的提升。

          CAS看起來很爽,但是會導(dǎo)致“ABA問題”。

          CAS算法實現(xiàn)一個重要前提需要取出內(nèi)存中某時刻的數(shù)據(jù),而在下時刻比較并替換,那么在這個時間差類會導(dǎo)致數(shù)據(jù)的變化

          比如說一個線程one從內(nèi)存位置V中取出A,這時候另一個線程two也從內(nèi)存中取出A,并且two進行了一些操作變成了B,然后two又將V位置的數(shù)據(jù)變成A,這時候線程one進行CAS操作發(fā)現(xiàn)內(nèi)存中仍然是A,然后one操作成功。盡管線程one的CAS操作成功,但是不代表這個過程就是沒有問題的。如果鏈表的頭在變化了兩次后恢復(fù)了原值,但是不代表鏈表就沒有變化。因此前面提到的原子操作AtomicStampedReference/AtomicMarkableReference就很有用了。這允許一對變化的元素進行原子操作。


          評論

          # re: [轉(zhuǎn)]CAS原理  回復(fù)  更多評論   

          2012-10-16 17:24 by 超凡
          好東西!
          主站蜘蛛池模板: 绥化市| 东丽区| 南城县| 甘谷县| 张家川| 大理市| 宿迁市| 荥阳市| 囊谦县| 安丘市| 双桥区| 饶平县| 夏河县| 门头沟区| 阳新县| 衡东县| 南澳县| 堆龙德庆县| 昭通市| 宜川县| 安乡县| 淮阳县| 锡林郭勒盟| 邹城市| 龙江县| 海晏县| 临湘市| 寻甸| 西宁市| 金寨县| 大荔县| 丰县| 嘉禾县| 乡宁县| 会理县| 明星| 车致| 陈巴尔虎旗| 宜川县| 米脂县| 灵武市|