日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷解決方案
從JUC源碼看CAS,我做了個(gè)筆記......

前言

創(chuàng)新互聯(lián)主要從事成都網(wǎng)站設(shè)計(jì)、成都網(wǎng)站建設(shè)、外貿(mào)網(wǎng)站建設(shè)、網(wǎng)頁(yè)設(shè)計(jì)、企業(yè)做網(wǎng)站、公司建網(wǎng)站等業(yè)務(wù)。立足成都服務(wù)廣陽(yáng),10余年網(wǎng)站建設(shè)經(jīng)驗(yàn),價(jià)格優(yōu)惠、服務(wù)專業(yè),歡迎來(lái)電咨詢建站服務(wù):18982081108

" JUC包下大量使用了CAS,工作和面試中也經(jīng)常遇到CAS,包括說(shuō)到樂(lè)觀鎖,也不可避免的想起CAS,那CAS究竟是什么? "

1.什么是CAS?

說(shuō)到CAS,基本上都會(huì)想到樂(lè)觀鎖、AtomicInteger、Unsafe ...

當(dāng)然也有可能啥也沒(méi)想到!

不管你們?cè)趺聪耄?我第一印象是樂(lè)觀鎖,畢竟做交易更新交易狀態(tài)經(jīng)常用到樂(lè)觀鎖,就自然想到這個(gè)SQL:

 
 
 
 
  1. update trans_order 
  2. set order_status = 1 
  3. where order_no = 'xxxxxxxxxxx' and order_status = 0;

其實(shí)就是 set和where里面都攜帶order_status。

那什么是CAS?

CAS就是Compare-and-Swap,即比較并替換,在并發(fā)算法時(shí)常用,并且在JUC(java.util.concurrent)包下很多類都使用了CAS。

非常常見(jiàn)的問(wèn)題就是多線程操作i++問(wèn)題。一般解決辦法就是添加 synchronized 關(guān)鍵字修飾,當(dāng)然也可以使用 AtomicInteger 代碼舉例如下:

 
 
 
 
  1. public class CasTest {
  2.     private static final CountDownLatch LATCH = new CountDownLatch(10);
  3.     private static int NUM_I = 0;
  4.     private static volatile int NUM_J = 0;
  5.     private static final AtomicInteger NUM_K = new AtomicInteger(0);
  6.     public static void main(String[] args) throws InterruptedException {
  7.         ExecutorService threadPool = Executors.newFixedThreadPool(10);
  8.         for (int i = 0; i < 10; i++) {
  9.             threadPool.execute(new Runnable() {
  10.                 public void run() {
  11.                     for (int j = 0; j < 10000; j++) {
  12.                         NUM_I++;
  13.                         NUM_J++;
  14.                         NUM_K.incrementAndGet();
  15.                     }
  16.                     LATCH.countDown();
  17.                 }
  18.             });
  19.         }
  20.         LATCH.await();
  21.         System.out.println("NUM_I = " + NUM_I);
  22.         System.out.println("NUM_J = " + NUM_J);
  23.         System.out.println("NUM_K = " + NUM_K.get());
  24.         threadPool.shutdown();
  25.     }
  26. }

下面就從AtomicInteger開(kāi)始了解CAS。

2.源碼分析

 
 
 
 
  1. public class AtomicInteger extends Number implements java.io.Serializable {
  2.     private static final long serialVersionUID = 6214790243416807050L;
  3.     // setup to use Unsafe.compareAndSwapInt for updates
  4.     private static final Unsafe unsafe = Unsafe.getUnsafe();
  5.     private static final long valueOffset;
  6.     static {
  7.         try {
  8.             valueOffset = unsafe.objectFieldOffset
  9.                 (AtomicInteger.class.getDeclaredField("value"));
  10.         } catch (Exception ex) { throw new Error(ex); }
  11.     }
  12.     private volatile int value;
  13.     public final int incrementAndGet() {
  14.         return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
  15.     }
  16.     public final int decrementAndGet() {
  17.         return unsafe.getAndAddInt(this, valueOffset, -1) - 1;
  18.     }
  19. }

可以看出里面使用了Unsafe類下的getAndAddInt方法,Unsafe類很多方法是本地(native)方法,主要是硬件級(jí)別的原子操作。

 
 
 
 
  1. /**
  2.  * @param var1 當(dāng)前對(duì)象
  3.  * @param var2 當(dāng)前對(duì)象在內(nèi)存偏移量,Unsafe可以根據(jù)內(nèi)存偏移地址獲取數(shù)據(jù)
  4.  * @param var4 操作值
  5.  * @return
  6.  */
  7. public final int getAndAddInt(Object var1, long var2, int var4) {
  8.     int var5;
  9.     do {
  10.         // 獲取在var1在內(nèi)存的值
  11.         var5 = this.getIntVolatile(var1, var2);
  12.         // 將var1賦值為var5+var4, 賦值時(shí)會(huì)判斷var1是否為var5
  13.     } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));
  14.     return var5;
  15. }
  16. // 原子操作
  17. public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);

至于 compareAndSwapInt 的分析就忽略了。

看完代碼過(guò)程其實(shí)就是:

  •  比較var1的值是否為var4,是的話將var1更新為var5。
  • 如果不是的話就一直循環(huán),直到var1是var4。

3.問(wèn)題總結(jié)

  • 這要是一直獲取不到,豈不是一直循環(huán)。線程多的情況下,會(huì)自旋很長(zhǎng)時(shí)間,導(dǎo)致浪費(fèi)資源。
  • 你更新了, 我又給你更新回去了,你也不知道。ABA問(wèn)題!比如像這樣,A想更新值為a,還未搶到資源,這時(shí)候B進(jìn)行了更新,將對(duì)象更新為了b,然后又馬上更新回了a, 這時(shí)候A是什么都不知道的。

以樂(lè)觀鎖舉例:

 
 
 
 
  1. -- 0 -> 1
  2. update trans_order 
  3. set order_status = 1 
  4. where order_no = 'xxxxxxxxxxx' and order_status = 0;
  5. -- 1 -> 0
  6. update trans_order 
  7. set order_status = 1 
  8. where order_no = 'xxxxxxxxxxx' and order_status = 0;
  9. -- 0 -> 1
  10. update trans_order 
  11. set order_status = 1 
  12. where order_no = 'xxxxxxxxxxx' and order_status = 0;

解決辦法可以添加version進(jìn)行版本號(hào)控制。

 
 
 
 
  1. -- 0 -> 1
  2. update trans_order 
  3. set order_status = 1 
  4. where order_no = 'xxxxxxxxxxx' and order_status = 0 and version = 0;
  5. -- 1 -> 0
  6. update trans_order 
  7. set order_status = 1 
  8. where order_no = 'xxxxxxxxxxx' and order_status = 0 and version = 1;
  9. -- 0 -> 1
  10. update trans_order 
  11. set order_status = 1 
  12. where order_no = 'xxxxxxxxxxx' and order_status = 0 and version = 0;

代碼中可以看 AtomicStampedReference 類:

 
 
 
 
  1. /**
  2.  * 以原子方式設(shè)置該引用和標(biāo)志給定的更新值的值,
  3.  * 如果當(dāng)前引用==預(yù)期的引用,并且當(dāng)前標(biāo)志==預(yù)期標(biāo)志。
  4.  *
  5.  * @param expectedReference 預(yù)期引用
  6.  * @param newReference 更新的值
  7.  * @param expectedStamp 預(yù)期標(biāo)志
  8.  * @param newStamp 更新的標(biāo)志
  9.  * @return {@code true} if successful
  10.  */
  11. public boolean compareAndSet(V   expectedReference,
  12.                              V   newReference,
  13.                              int expectedStamp,
  14.                              int newStamp) {
  15.     Pair current = pair;
  16.     return
  17.         expectedReference == current.reference &&
  18.         expectedStamp == current.stamp &&
  19.         ((newReference == current.reference &&
  20.             newStamp == current.stamp) ||
  21.             casPair(current, Pair.of(newReference, newStamp)));
  22. }

其實(shí)就是額外增加一個(gè)標(biāo)志(stamp)來(lái)防止ABA的問(wèn)題, 類似樂(lè)觀鎖的version。

本文轉(zhuǎn)載自微信公眾號(hào)「劉志航」,可以通過(guò)以下二維碼關(guān)注。轉(zhuǎn)載本文請(qǐng)聯(lián)系劉志航公眾號(hào)。


分享題目:從JUC源碼看CAS,我做了個(gè)筆記......
當(dāng)前地址:http://www.5511xx.com/article/djpsgco.html