时间:2021-05-19
本文主要研究的是关于Java中ABA问题及避免的相关内容,具体如下。
在《Java并发实战》一书的第15章中有一个用原子变量实现的并发栈,代码如下:
public class Node { public final String item; public Node next; public Node(String item){ this.item = item; }}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; }}这个例子并不会引发ABA问题,至于为什么不会,后面再讲解,下面先讲一下ABA问题
什么是ABA?
引用原书的话:如果在算法中的节点可以被循环使用,那么在使用“比较并交换”指令就可能出现这种问题,在CAS操作中将判断“V的值是否仍然为A?”,并且如果是的话就继续执行更新操作,在某些算法中,如果V的值首先由A变为B,再由B变为A,那么CAS将会操作成功
ABA的例子
有时候,ABA造成的后果很严重,下面将并发栈的例子修改一下,看看ABA会造成什么问题:
public class Node { public final String item; public Node next; public Node(String item){ this.item = item; }}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,现在直接传入Node,这样就符合了“在算法中的节点可以被循环使用”这个要求
2、pop方法的sleep,这是模拟线程的执行情况,以便观察结果
我们先往stack中压入两个Node:
ConcurrentStack stack = new ConcurrentStack(); stack.push(new Node("A")); stack.push(new Node("B"));然后创建两个线程来执行出入栈的操作
线程A先执行出栈:让NodeA出栈
stack.pop(3);因为某些原因,线程A执行出栈比较久,用了3s
线程B执行出栈之后再入栈:先然NodeA和NodeB出栈,然后让NodeD,NodeC,NodeA入栈(NodeA在栈顶)
Node A = stack.pop(0); stack.pop(0); stack.push(new Node("D")); stack.push(new Node("C")); stack.push(A);注意:线程B实现了节点的循环利用,它先将栈里面的内容全部出栈,然后入栈,最后栈顶的内容是之前出栈的Node
线程B执行完这些动作之后,线程A才执行CAS,此时CAS是可以执行成功的
按照原来的想法,线程A和B执行之后,stack的内容应该是:C和D,C在栈顶,但这里的执行结果却是Stack中什么都没有,这就是ABA问题
如何避免ABA问题
Java中提供了AtomicStampedReference和AtomicMarkableReference来解决ABA问题
AtomicStampedReference可以原子更新两个值:引用和版本号,通过版本号来区别节点的循环使用,下面看AtomicStampedReference的例子:
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(); } }}注意:不能使用注释中的方式,否则就和单纯使用原子变量没有区别了
AtomicMarkableReference可以原子更新一个布尔类型的标记位和引用类型,看下面的例子:
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问题及避免的全部内容,希望对大家有所帮助。感兴趣的朋友可以继续参阅本站其他相关专题,如有不足之处,欢迎留言指出。感谢朋友们对本站的支持!
声明:本页内容来源网络,仅供用户参考;我单位不保证亦不表示资料全面及准确无误,也不保证亦不表示这些资料为最新信息,如因任何原因,本网内容或者用户因倚赖本网内容造成任何损失或损害,我单位将不会负任何法律责任。如涉及版权问题,请提交至online#300.cn邮箱联系删除。
浅谈java内存模型不同的平台,内存模型是不一样的,但是jvm的内存模型规范是统一的。其实java的多线程并发问题最终都会反映在java的内存模型上,所谓线程安
浅谈java执行jar包中的main方法通过OneJar或Maven打包后jar文件,用命令:java-jar****.jar执行后总是运行指定的主方法,如果j
本文介绍了浅谈Java的两种多线程实现方式,分享给大家。具有如下:一、创建多线程的两种方式Java中,有两种方式可以创建多线程:1通过继承Thread类,重写T
Java中可以使用关键字synchronized进行线程同步控制,实现关键资源顺序访问,避免由于多线程并发执行导致的数据不一致性等问题。synchronized
网店的转让,尤其大家关心的问题是安全及售后问题。为确保淘宝店铺顺利转让,避免后续没必要问题的产生,今天主要和各位分享淘宝店铺转让的安全及售后问题。一:淘宝店铺转