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

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

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
什么是ABA問題?Java里面的原生解決方案是什么?原理是什么?

[[380084]]

成都創(chuàng)新互聯(lián)公司專注于企業(yè)成都全網(wǎng)營銷推廣、網(wǎng)站重做改版、留壩網(wǎng)站定制設(shè)計(jì)、自適應(yīng)品牌網(wǎng)站建設(shè)、H5網(wǎng)站設(shè)計(jì)電子商務(wù)商城網(wǎng)站建設(shè)、集團(tuán)公司官網(wǎng)建設(shè)、成都外貿(mào)網(wǎng)站建設(shè)、高端網(wǎng)站制作、響應(yīng)式網(wǎng)頁設(shè)計(jì)等建站業(yè)務(wù),價(jià)格優(yōu)惠性價(jià)比高,為留壩等各大城市提供網(wǎng)站開發(fā)制作服務(wù)。

 AtomicStampedReference是一個(gè)帶有時(shí)間戳的對(duì)象引用,能很好的解決CAS機(jī)制中的ABA問題,這篇文章將通過案例對(duì)其介紹分析。

一、ABA問題

ABA問題是CAS機(jī)制中出現(xiàn)的一個(gè)問題,他的描述是這樣的。我們直接畫一張圖來演示,

什么意思呢?就是說一個(gè)線程把數(shù)據(jù)A變?yōu)榱薆,然后又重新變成了A。此時(shí)另外一個(gè)線程讀取的時(shí)候,發(fā)現(xiàn)A沒有變化,就誤以為是原來的那個(gè)A。這就是有名的ABA問題。ABA問題會(huì)帶來什么后果呢?我們舉個(gè)例子。

一個(gè)小偷,把別人家的錢偷了之后又還了回來,還是原來的錢嗎,ABA問題也一樣,如果不好好解決就會(huì)帶來大量的問題。最常見的就是資金問題,也就是別人如果挪用了你的錢,在你發(fā)現(xiàn)之前又還了回來。但是別人卻已經(jīng)觸犯了法律。

如何去解決這個(gè)ABA問題呢,就是使用今天所說的AtomicStampedReference。

二、AtomicStampedReference

1、問題解決

我們先給出一個(gè)ABA的例子,對(duì)ABA問題進(jìn)行場(chǎng)景重現(xiàn)。

 
 
 
 
  1. public class AtomicTest { 
  2.  private static AtomicInteger index = new AtomicInteger(10); 
  3.  public static void main(String[] args) { 
  4.   new Thread(() -> { 
  5.    index.compareAndSet(10, 11); 
  6.    index.compareAndSet(11, 10); 
  7.    System.out.println(Thread.currentThread().getName()+ 
  8.      ":10->11->10"); 
  9.   },"張三").start(); 
  10.    
  11.   new Thread(() -> { 
  12.    try { 
  13.     TimeUnit.SECONDS.sleep(2); 
  14.     boolean isSuccess = index.compareAndSet(10, 12); 
  15.     System.out.println(Thread.currentThread().getName()+ 
  16.       ":index是預(yù)期的10嘛,"+isSuccess 
  17.       +"   設(shè)置的新值是:"+index.get()); 
  18.    } catch (InterruptedException e) { 
  19.     e.printStackTrace(); 
  20.    } 
  21.   },"李四").start(); 
  22.  } 

在上面的代碼中,我們使用張三線程,對(duì)index10->11->10的變化,然后李四線程讀取index觀察是否有變化,并設(shè)置新值。運(yùn)行一下看看結(jié)果:

這個(gè)案例重現(xiàn)了ABA的問題場(chǎng)景,下面我們看如何使用AtomicStampedReference解決這個(gè)問題的。

 
 
 
 
  1. public class AtomicTest2 { 
  2.  private static AtomicInteger index = new AtomicInteger(10); 
  3.  static AtomicStampedReference stampRef  
  4.        = new AtomicStampedReference(10, 1); 
  5.  public static void main(String[] args) { 
  6.   new Thread(() -> { 
  7.    int stamp = stampRef.getStamp(); 
  8.    System.out.println(Thread.currentThread().getName()  
  9.      + " 第1次版本號(hào): " + stamp); 
  10.    stampRef.compareAndSet(10, 11,stampRef.getStamp(),stampRef.getStamp()+1); 
  11.    System.out.println(Thread.currentThread().getName()  
  12.      + " 第2次版本號(hào): " + stampRef.getStamp()); 
  13.    stampRef.compareAndSet(11, 10,stampRef.getStamp(),stampRef.getStamp()+1); 
  14.    System.out.println(Thread.currentThread().getName()  
  15.      + " 第3次版本號(hào): " + stampRef.getStamp()); 
  16.   },"張三").start(); 
  17.    
  18.   new Thread(() -> { 
  19.    try { 
  20.     int stamp = stampRef.getStamp(); 
  21.     System.out.println(Thread.currentThread().getName()  
  22.       + " 第1次版本號(hào): " + stamp); 
  23.     TimeUnit.SECONDS.sleep(2); 
  24.     boolean isSuccess =stampRef.compareAndSet(10, 12, 
  25.       stampRef.getStamp(),stampRef.getStamp()+1); 
  26.     System.out.println(Thread.currentThread().getName()  
  27.       + " 修改是否成功: "+ isSuccess+" 當(dāng)前版本 :" + stampRef.getStamp()); 
  28.     System.out.println(Thread.currentThread().getName()  
  29.       + " 當(dāng)前實(shí)際值: " + stampRef.getReference()); 
  30.    } catch (InterruptedException e) { 
  31.     e.printStackTrace(); 
  32.    } 
  33.   },"李四").start(); 
  34.  } 

上面的代碼我們?cè)賮矸治鲆幌?,我們?huì)發(fā)現(xiàn)AtomicStampedReference里面增加了一個(gè)時(shí)間戳,也就是說每一次修改只需要設(shè)置不同的版本好即可。我們先運(yùn)行一邊看看:

這里使用的是AtomicStampedReference的compareAndSet函數(shù),這里面有四個(gè)參數(shù):

compareAndSet(V expectedReference, V newReference, int expectedStamp, int newStamp)。

(1)第一個(gè)參數(shù)expectedReference:表示預(yù)期值。

(2)第二個(gè)參數(shù)newReference:表示要更新的值。

(3)第三個(gè)參數(shù)expectedStamp:表示預(yù)期的時(shí)間戳。

(4)第四個(gè)參數(shù)newStamp:表示要更新的時(shí)間戳。

這個(gè)compareAndSet方法到底是如何實(shí)現(xiàn)的,我們深入到源碼中看看。

2、源碼分析

 
 
 
 
  1. public boolean compareAndSet(V   expectedReference, 
  2.                                 V   newReference, 
  3.                                 int expectedStamp, 
  4.                                 int newStamp) { 
  5.        Pair current = pair; 
  6.        return 
  7.            expectedReference == current.reference && 
  8.            expectedStamp == current.stamp && 
  9.            ((newReference == current.reference && 
  10.              newStamp == current.stamp) || 
  11.             casPair(current, Pair.of(newReference, newStamp))); 
  12.    } 

剛剛這四個(gè)參數(shù)的意思已經(jīng)說了,我們主要關(guān)注的就是實(shí)現(xiàn),首先我們看到的就是這個(gè)Pair,因此想要弄清楚,我們?cè)倏纯催@個(gè)Pair是什么,

 
 
 
 
  1. private static class Pair { 
  2.      final T reference; 
  3.      final int stamp; 
  4.      private Pair(T reference, int stamp) { 
  5.          this.reference = reference; 
  6.          this.stamp = stamp; 
  7.      } 
  8.      static  Pair of(T reference, int stamp) { 
  9.          return new Pair(reference, stamp); 
  10.      } 
  11.  } 

在這里我們會(huì)發(fā)現(xiàn)Pair里面只是包存了值reference和時(shí)間戳stamp。

在compareAndSet方法中最后還調(diào)用了casPair方法,從名字就可以看到,主要是使用CAS機(jī)制更新新的值reference和時(shí)間戳stamp。我們可以進(jìn)入這個(gè)方法中看看。

 
 
 
 
  1. //底層調(diào)用的是UNSAFE的compareAndSwapObject方法 
  2.  
  3.  private boolean casPair(Pair cmp, Pair val) { 
  4.      return UNSAFE.compareAndSwapObject(this, pairOffset, cmp, val); 
  5.  } 

三、總結(jié)

其實(shí)除了AtomicStampedReference類,還有一個(gè)原子類也可以解決,就是AtomicMarkableReference,它不是維護(hù)一個(gè)版本號(hào),而是維護(hù)一個(gè)boolean類型的標(biāo)記,用法沒有AtomicStampedReference靈活。因此也只是在特定的場(chǎng)景下使用。

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

 


標(biāo)題名稱:什么是ABA問題?Java里面的原生解決方案是什么?原理是什么?
標(biāo)題路徑:http://www.5511xx.com/article/dpcdoch.html