一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - 淺談Java中ABA問題及避免

淺談Java中ABA問題及避免

2021-03-22 14:47li954644351 Java教程

這篇文章主要介紹了淺談Java中ABA問題及避免,具有一定借鑒價值,需要的朋友可以參考下

本文主要研究的是關于Java中ABA問題及避免的相關內容,具體如下。

在《Java并發(fā)實戰(zhàn)》一書的第15章中有一個用原子變量實現(xiàn)的并發(fā)棧,代碼如下:

?
1
2
3
4
5
6
7
public class Node {
    public final String item;
    public Node next;
    public Node(String item){
        this.item = item;
    }
}
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class ConcurrentStack {
    AtomicReference<Node> top = new AtomicReference<Node>();
    public void push(String item){
        Node newTop = new Node(item);
        Node oldTop;
        do{
            oldTop = top.get();
            newTop.next = oldTop;
        }
        while(!top.compareAndSet(oldTop, newTop));
    }
    public String pop(){
        Node newTop;
        Node oldTop;
        do{
            oldTop = top.get();
            if(oldTop == null){
                return null;
            }
            newTop = oldTop.next;
        }
        while(!top.compareAndSet(oldTop, newTop));
        return oldTop.item;
    }
}

這個例子并不會引發(fā)ABA問題,至于為什么不會,后面再講解,下面先講一下ABA問題

什么是ABA?

引用原書的話:如果在算法中的節(jié)點可以被循環(huán)使用,那么在使用“比較并交換”指令就可能出現(xiàn)這種問題,在CAS操作中將判斷“V的值是否仍然為A?”,并且如果是的話就繼續(xù)執(zhí)行更新操作,在某些算法中,如果V的值首先由A變?yōu)锽,再由B變?yōu)锳,那么CAS將會操作成功

ABA的例子

有時候,ABA造成的后果很嚴重,下面將并發(fā)棧的例子修改一下,看看ABA會造成什么問題:

?
1
2
3
4
5
6
7
public class Node {
    public final String item;
    public Node next;
    public Node(String item){
        this.item = item;
    }
}
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class ConcurrentStack {
    AtomicReference<Node> top = new AtomicReference<Node>();
    public void push(Node node){
        Node oldTop;
        do{
            oldTop = top.get();
            node.next = oldTop;
        }
        while(!top.compareAndSet(oldTop, node));
    }
    public Node pop(int time){
        Node newTop;
        Node oldTop;
        do{
            oldTop = top.get();
            if(oldTop == null){
                return null;
            }
            newTop = oldTop.next;
            TimeUnit.SECONDS.sleep(time);
        }
        while(!top.compareAndSet(oldTop, newTop));
        return oldTop;
    }
}

注意這里的變化,Node基本沒有變化

重點關注ConcurrentStack的變化

1、push方法:原來是使用內容構造Node,現(xiàn)在直接傳入Node,這樣就符合了“在算法中的節(jié)點可以被循環(huán)使用”這個要求

2、pop方法的sleep,這是模擬線程的執(zhí)行情況,以便觀察結果

我們先往stack中壓入兩個Node:

?
1
2
3
ConcurrentStack stack = new ConcurrentStack();
stack.push(new Node("A"));
stack.push(new Node("B"));

然后創(chuàng)建兩個線程來執(zhí)行出入棧的操作

線程A先執(zhí)行出棧:讓NodeA出棧

?
1
stack.pop(3);

因為某些原因,線程A執(zhí)行出棧比較久,用了3s

線程B執(zhí)行出棧之后再入棧:先然NodeA和NodeB出棧,然后讓NodeD,NodeC,NodeA入棧(NodeA在棧頂)

?
1
2
3
4
5
Node A = stack.pop(0);
stack.pop(0);
stack.push(new Node("D"));
stack.push(new Node("C"));
stack.push(A);

注意:線程B實現(xiàn)了節(jié)點的循環(huán)利用,它先將棧里面的內容全部出棧,然后入棧,最后棧頂?shù)膬热菔侵俺鰲5腘ode

線程B執(zhí)行完這些動作之后,線程A才執(zhí)行CAS,此時CAS是可以執(zhí)行成功的

按照原來的想法,線程A和B執(zhí)行之后,stack的內容應該是:C和D,C在棧頂,但這里的執(zhí)行結果卻是Stack中什么都沒有,這就是ABA問題

如何避免ABA問題

Java中提供了AtomicStampedReference和AtomicMarkableReference來解決ABA問題

AtomicStampedReference可以原子更新兩個值:引用和版本號,通過版本號來區(qū)別節(jié)點的循環(huán)使用,下面看AtomicStampedReference的例子:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
public class ConcurrentStack {
    AtomicStampedReference<Node> top = new AtomicStampedReference<Node>(null,0);
    public void push(Node node){
        Node oldTop;
        int v;
        do{
            v=top.getStamp();
            oldTop = top.getReference();
            node.next = oldTop;
        }
        while(!top.compareAndSet(oldTop, node,v,v+1));
        //   }while(!top.compareAndSet(oldTop, node,top.getStamp(),top.getStamp()+1));
    }
    public Node pop(int time){
        Node newTop;
        Node oldTop;
        int v;
        do{
            v=top.getStamp();
            oldTop = top.getReference();
            if(oldTop == null){
                return null;
            }
            newTop = oldTop.next;
            try {
                TimeUnit.SECONDS.sleep(time);
            }
            catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        while(!top.compareAndSet(oldTop, newTop,v,v+1));
        //   }while(!top.compareAndSet(oldTop, newTop,top.getStamp(),top.getStamp()));
        return oldTop;
    }
    public void get(){
        Node node = top.getReference();
        while(node!=null){
            System.out.println(node.getItem());
            node = node.getNode();
        }
    }
}

注意:不能使用注釋中的方式,否則就和單純使用原子變量沒有區(qū)別了

AtomicMarkableReference可以原子更新一個布爾類型的標記位和引用類型,看下面的例子:

?
1
2
3
4
5
6
7
8
9
10
11
AtomicMarkableReference<Node> top = new AtomicMarkableReference<Node>(null,true);
public void push(Node node){
    Node oldTop;
    Boolean v;
    do{
        v=top.isMarked();
        oldTop = top.getReference();
        node.next = oldTop;
    }
    while(!top.compareAndSet(oldTop, node,v,!v));
}

總結

以上就是本文關于淺談Java中ABA問題及避免的全部內容,希望對大家有所幫助。感興趣的朋友可以繼續(xù)參閱本站其他相關專題,如有不足之處,歡迎留言指出。感謝朋友們對本站的支持!

原文鏈接:http://blog.csdn.net/li954644351/article/details/50511879

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 男女视频在线观看 | 精品视频免费在线 | 美味情缘韩国在线观看视频 | 国产精品1| 波多洁野衣一二区三区 | 美女用手扒开粉嫩的屁股 | 叛佛 作者满栀小说免费阅读 | 国产第一福利影院 | a一区二区三区视频 | 国产精品久久久久毛片真精品 | 日本一区二区三区精品 | 天堂男人在线 | 紧身牛仔裤美女被啪啪久久网 | 36美女厕所撒尿全过程 | 男人把大ji巴放进女人小说 | 91麻豆精品国产片在线观看 | 日本xxx在线观看免费播放 | 欧美在线播放成人免费 | 添逼逼视频 | 亚洲AV无码一区二区三区乱子伦 | 亚洲精品中文字幕第一区 | 九九九久久久 | 欧美日韩综合一区 | 男人在线影院 | gogort人体的最新网站 | 精品亚洲永久免费精品 | 日韩成人一区ftp在线播放 | 亚洲网色 | 奇米影视小说 | 午夜福到在线4国产 | 亚洲免费在线看 | 国产一卡2卡3卡四卡精品网站 | 日本人成在线视频免费播放 | a级毛片毛片免费很很综合 a级黄色视屏 | 日本欧美不卡一区二区三区在线 | 思思玖玖 | 韩国女主播在线大尺无遮挡 | ak福利午夜在线观看 | 欧美精品亚洲精品日韩1818 | 国产一区二区三区高清 | futa巨大好爽好长 |