多多色-多人伦交性欧美在线观看-多人伦精品一区二区三区视频-多色视频-免费黄色视屏网站-免费黄色在线

國內(nèi)最全I(xiàn)T社區(qū)平臺 聯(lián)系我們 | 收藏本站
阿里云優(yōu)惠2
您當(dāng)前位置:首頁 > 互聯(lián)網(wǎng) > 聊聊高并發(fā)(十二)分析java.util.concurrent.atomic.AtomicStampedReference源碼來看如何解決CAS的ABA問題

聊聊高并發(fā)(十二)分析java.util.concurrent.atomic.AtomicStampedReference源碼來看如何解決CAS的ABA問題

來源:程序員人生   發(fā)布時(shí)間:2014-11-11 08:20:24 閱讀次數(shù):3403次

在聊聊高并發(fā)(101)實(shí)現(xiàn)幾種自旋鎖(5)中使用了java.util.concurrent.atomic.AtomicStampedReference原子變量指向工作隊(duì)列的隊(duì)尾,為什么使用AtomicStampedReference原子變量而不是使用AtomicReference是由于這個(gè)實(shí)現(xiàn)中等待隊(duì)列的同1個(gè)節(jié)點(diǎn)具有不同的狀態(tài),而同1個(gè)節(jié)點(diǎn)會屢次進(jìn)出工作隊(duì)列,這就有可能出現(xiàn)出現(xiàn)ABA問題。


熟習(xí)并發(fā)編程的同學(xué)應(yīng)當(dāng)知道CAS操作存在ABA問題。我們先看下CAS操作。

CAS(Compare and Swap) 比較并交換操作是1個(gè)3元操作: 目標(biāo)地址的值T(arget),期望值E(xpected),實(shí)際值R(eal),

1. 只有當(dāng)目標(biāo)值T == 期望值E時(shí),才會把目標(biāo)值T設(shè)置為實(shí)際值R,否則不改變目標(biāo)值

2. 不管目標(biāo)值是不是改變,都返回之前的目標(biāo)值T


類似以下的邏輯:

package com.zc.lock; public class CAS { private int value; public synchronized int get(){ return value; } public synchronized int compareAndSwap(int expected, int real){ int oldValue = value; if(value == expected){ value = real; } return oldValue; } public synchronized boolean compareAndSet(int expected, int real){ return (expected == compareAndSwap(expected, real)); } }

CAS只比較期望值和目標(biāo)值是不是相當(dāng),相當(dāng)就設(shè)置新值。那末ABA問題就來了:

1. 由于CAS只是值比較,比如目標(biāo)是A, 期望值也是A, 那末CAS操作會成功。但是這時(shí)候候目標(biāo)A可能不是原來的那個(gè)A了,它多是A變成了B,再變成了A。所以叫ABA問題,很形象。ABA問題可能會使程序出錯(cuò),比如限時(shí)有界隊(duì)列鎖中的節(jié)點(diǎn)有幾個(gè)狀態(tài),雖然援用值是A,但是可能對象的狀態(tài)已變了,這時(shí)候候的A實(shí)際已不是原來的A了

2. 需要注意的是ABA問題不是說CAS操作的進(jìn)程中A變成了ABA,CAS操作是原子操作,不會被打斷。ABA問題場景以下:

先獲得了A的值,然后再CAS(A, R), 這時(shí)候候CAS中的A實(shí)際指向的對象的狀態(tài)可能和它剛?cè)〉玫臅r(shí)候的狀態(tài)已發(fā)送了改變。


</pre><pre name="code" class="java">A a = ref.get(); // 根據(jù)a的狀態(tài)做1些操作 // do something // CAS,這時(shí)候候會出現(xiàn)ABA問題,a指向的對象可能已變了 ref.compareAndSet(a, b)

解決ABA問題方法就是給狀態(tài)設(shè)置時(shí)間戳,這是并發(fā)中加樂觀鎖的常見做法,如果狀態(tài)的時(shí)間戳產(chǎn)生了改變,證明已不是原來的對象了,所以操作失敗

// 用int做時(shí)間戳 AtomicStampedReference<QNode> tail = new AtomicStampedReference<CompositeLock.QNode>(null, 0); int[] currentStamp = new int[1]; // currentStamp中返回了時(shí)間戳信息 QNode tailNode = tail.get(currentStamp); tail.compareAndSet(tailNode, null, currentStamp[0], currentStamp[0] + 1)

下面我們來看1下java.util.concurrent.atomic.AtomicStampedReference的源代碼是如何實(shí)現(xiàn)的。

下面代碼來自JDK1.7,條理很清晰,實(shí)現(xiàn)有幾個(gè)要點(diǎn):

1. 創(chuàng)建1個(gè)Pair類來記錄對象援用和時(shí)間戳信息,采取int作為時(shí)間戳,實(shí)際使用的時(shí)候時(shí)間戳信息要做成自增的,否則時(shí)間戳如果重復(fù),還會出現(xiàn)ABA的問題。這個(gè)Pair對象是不可變對象,所有的屬性都是final的, of方法每次返回1個(gè)新的不可變對象

2. 使用1個(gè)volatile類型的援用指向當(dāng)前的Pair對象,1旦volatile援用產(chǎn)生變化,變化對所有線程可見

3. set方法時(shí),當(dāng)要設(shè)置的對象和當(dāng)前Pair對象不1樣時(shí),新建1個(gè)不可變的Pair對象

4. compareAndSet方法中,只有期望對象的援用和版本號和目標(biāo)對象的援用和版本好都1樣時(shí),才會新建1個(gè)Pair對象,然后用新建的Pair對象和原理的Pair對象做CAS操作

5. 實(shí)際的CAS操作比較的是當(dāng)前的pair對象和新建的pair對象,pair對象封裝了援用和時(shí)間戳信息


private static class Pair<T> { final T reference; final int stamp; private Pair(T reference, int stamp) { this.reference = reference; this.stamp = stamp; } static <T> Pair<T> of(T reference, int stamp) { return new Pair<T>(reference, stamp); } } private volatile Pair<V> pair; public AtomicStampedReference(V initialRef, int initialStamp) { pair = Pair.of(initialRef, initialStamp); } public void set(V newReference, int newStamp) {         Pair<V> current = pair;         if (newReference != current.reference || newStamp != current.stamp)             this.pair = Pair.of(newReference, newStamp);     } public boolean compareAndSet(V   expectedReference,                                  V   newReference,                                  int expectedStamp,                                  int newStamp) {         Pair<V> current = pair;         return             expectedReference == current.reference &&             expectedStamp == current.stamp &&             ((newReference == current.reference &&               newStamp == current.stamp) ||              casPair(current, Pair.of(newReference, newStamp)));     } private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe();     private static final long pairOffset =         objectFieldOffset(UNSAFE, "pair", AtomicStampedReference.class);     private boolean casPair(Pair<V> cmp, Pair<V> val) {         return UNSAFE.compareAndSwapObject(this, pairOffset, cmp, val);     }








生活不易,碼農(nóng)辛苦
如果您覺得本網(wǎng)站對您的學(xué)習(xí)有所幫助,可以手機(jī)掃描二維碼進(jìn)行捐贈
程序員人生
------分隔線----------------------------
分享到:
------分隔線----------------------------
關(guān)閉
程序員人生
主站蜘蛛池模板: 高清视频在线观看+免费 | 亚洲视频免费看 | 欧美xxxx做受欧美精品 | 成人午夜又粗又硬有大 | 日本一区二区三区四区无限 | 国产偷v国产偷v亚洲高清 | 91精品国产综合久久久久 | 日韩成人免费视频播放 | 亚洲天堂中文字幕 | 狠狠色伊人亚洲综合第8页 狠狠色综合网 | 亚洲精品第一第二区 | 波多野结衣资源在线 | 尤物 在线播放 | hd欧美xxx欧美极品hd | 国产美女久久久亚洲 | 亚洲精品在线网址 | 国产成人啪午夜精品网站 | 日韩欧美中文字幕一区二区三区 | 老司机一二三区福利视频 | 国产精品爱久久久久久久 | 噜噜影院| 福利片视频区 | 国产成人亚洲精品2020 | 午夜精品久久久久久毛片 | 国产成人精品一区二区不卡 | 爱爱免费视频网站 | 福利视频一区二区 | 欧美高清在线视频在线99精品 | 亚洲视频免费 | 最近中文免费字幕在线播放 | 亚洲精品久久一区二区无卡 | 国产亚洲精品网站 | 亚洲精品国产第一区第二区国 | 欧美最爽乱淫视频播放黑人 | 性欧美高清精品video | 一二三四观看视频中文在线观看 | 一区二区视频在线观看免费的 | 欧美一级做一级做片性十三 | 大学生一级毛片高清版 | 欧美日韩在线精品一区二区三区 | 亚洲欧美一区二区三区九九九 |