java aba问题_JAVA与ABA问题

java aba问题_JAVA与ABA问题在 JAVA 并发编程实战 的第 15 4 4 节中看到了一些关于 ABA 问题的描述 有一篇文章摘录了书里的内容 书中有一段内容为 如果在算法中采用自己的方式来管理节点对象的内存 那么可能出现 ABA 问题 在这种情况下 即使链表的头结点仍然只想之前观察到的节点 那么也不足以说明链表的内容没有发生变化 如果通过垃圾回收器来管理链表节点仍然无法避免 ABA 问题 那么还有一个相对简单的解决方法 不是只是更新某个引用

在《JAVA并发编程实战》的第15.4.4节中看到了一些关于ABA问题的描述。有一篇文章摘录了书里的内容。

书中有一段内容为:

如果在算法中采用自己的方式来管理节点对象的内存,那么可能出现ABA问题。在这种情况下,即使链表的头结点仍然只想之前观察到的节点,那么也不足以说明链表的内容没有发生变化。如果通过垃圾回收器来管理链表节点仍然无法避免ABA问题,那么还有一个相对简单的解决方法:不是只是更新某个引用的值,而是更新两个值,包含一个引用和一个版本号。

这一段说到了“如果采用自己的方式管理节点对象的内存,可能出现ABA问题”,又说通过垃圾回收器来管理链表节点可能避免ABA问题。但是这些表述太简略,让我有些困惑。具体怎么样管理内存,会出现ABA问题?GC会什么可能会避免ABA问题?为什么只是“可能会避免”?

在JDK的ConcurrentLinkedQueue的源码注释中,有以下说法:

* This is a modification of the Michael & Scott algorithm,

* adapted for a garbage-collected environment, with support for

* interior node deletion (to support remove(Object)). For

* explanation, read the paper.

*

* Note that like most non-blocking algorithms in this package,

* this implementation relies on the fact that in garbage

* collected systems, there is no possibility of ABA problems due

* to recycled nodes, so there is no need to use “counted

* pointers” or related techniques seen in versions used in

* non-GC’ed settings.

里边有两点要注意的:

说这个类的实现是对”Michael & Scott”算法的一个修改,这个修改是基于ConcurrentLinkedList的实现存在于“垃圾回收的环境”。

说这个类的实现依赖于“在GC系统中,there is no possibility of ABA problems due to recycled nodes”。问题在于,什么叫”recycled nodes”?

好吧,那么在JAVA中怎么操作可能会现ABA问题呢?

假如有一个Queue(先别管它怎么实现),那么在以下情况下会出现ABA问题:

我们在CAS中比较对节点的引用 & 我们复用节点。假如queue初始的状态是A -> E。在变化后的状态是A -> X -> E。那么我们在CAS中比较对A的引用时,就无法看出状态的变化。“复用”,就是像这个例子一样,把同一个节点再次加个队列。

我们在CAS中比较对节点的引用 & 某个new出来的节点A2的地址恰好和A1的地址相同。

第一种情况不管GC环境还是非GC环境,都会造成ABA问题。所以GC只是可能会避免ABA问题,就像《JAVA并发编程实战》中说的一样。

GC环境和无GC的环境(如C++)的不同在于第二种情况。即,在JAVA中第,第二种情况是不可能发生的。原因在于,在我们用CAS比较A1和A2这两个引用时,暗含着的事实是——这两个引用存在,所以它们所引用的对象都是GC root可达的。那么在A1引用的对象还未被GC时,一个新new的对象是不可能和A1的对象有相同的地址的。所以A1 != A2。

所以,在JAVA的GC环境中,如果两个引用在CAS中被判断为相等,它们引用的肯定是同一个对象。但是,这种描述对于非GC环境不成立。

例如,在C++中,我们对指针(类比于JAVA中的引用)采用CAS操作,那么即使两个指针相同,他们也未必引用同一个对象,有可能是第一个指针所指向的内存被释放后,第二个对象恰好分配在相同地址的内存。

在维基百科上,给出了上面提到的第一种情况在C++中的一个例子。在这个例子中,复用节点的行为,可能会导致使用一个悬垂指针。

同时,维基百科也对第二种情况给出了描述:

A common case of the ABA problem is encountered when implementing a lock-free data structure. If an item is removed from the list, deleted, and then a new item is allocated and added to the list, it is common for the allocated object to be at the same location as the deleted object due to optimization. A pointer to the new item is thus sometimes equal to a pointer to the old item which is an ABA problem.

在ConcurrentLinkedList的实现中,并不存在复用节点的行为。在这个类的实现内部,以及它提供给用户的API,都无法使得节点被复用,而且这是JAVA环境中。所以ConcurrentLinkedList的实现中直接对node的引用进行CAS操作,而不必担心ABA问题。

例如,在offer的实现中(JDK1.7)

public boolean offer(E e) {

checkNotNull(e);

final Node newNode = new Node(e);

for (Node t = tail, p = t;;) {

Node q = p.next;

if (q == null) {

// p is last node

if (p.casNext(null, newNode)) {

// Successful CAS is the linearization point

// for e to become an element of this queue,

// and for newNode to become “live”.

if (p != t) // hop two nodes at a time

casTail(t, newNode); // Failure is OK.

return true;

}

// Lost CAS race to another thread; re-read next

}

else if (p == q)

// We have fallen off list. If tail is unchanged, it

// will also be off-list, in which case we need to

// jump to head, from which all live nodes are always

// reachable. Else the new tail is a better bet.

p = (t != (t = tail)) ? t : head;

else

// Check for tail updates after two hops.

p = (p != t && t != (t = tail)) ? t : q;

}

}

用if (p.casNext(null, newNode))来确保只有p是尾节点时,才将新结点链接在p的后边。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/229405.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月16日 下午4:47
下一篇 2026年3月16日 下午4:47


相关推荐

  • maven对应jdk版本_maven安装配置教程

    maven对应jdk版本_maven安装配置教程1.首先查看JDK版本号java-versionjavac-version2.查看maven版本号mvn-v查看maven相关的系统信息(包含使用的jdk)用:mvnhelp:system

    2022年8月22日
    7
  • 怎样把钱转入微众银行卡_微信支付怎么把钱提出来

    怎样把钱转入微众银行卡_微信支付怎么把钱提出来https://blog.csdn.net/baidu_37366055/article/details/81215962?utm_source=blogxgwz7后续需要使用,所以暂时转载记录一下

    2022年8月19日
    8
  • 搭建FCOS镜像

    搭建FCOS镜像FCOS 源码 https github com tianzhi0549 FCOSFCOSInst amp Requirements https github com tianzhi0549 FCOS blob master INSTALL md 一 建立 CUDA cudnn 镜像 githuboption 给出的是 CUDA10 2 的版本 其他版本也可 安装匹配的软件版本即可 结合本地环境 首先建立基础镜像 直接拉取 nvidiadocker 官方镜像作为我们的系统

    2026年3月17日
    1
  • Java开发工程师简历_工作业绩自我评价50字

    Java开发工程师简历_工作业绩自我评价50字面试Java工程师时一份好的简历是很必要的,简历当然少不了个人的自我评价了。下面学习啦小编给大家分享一些java工程师个人简历自我评价范文,希望能够帮到大家。更多热门的Java工程师面试简历、笔试题、薪资待遇☟欢迎赏析☟java工程师个人简历自我评价范文篇一具有很强的团队精神,有良好的组织和协调能力,有强烈的集体荣誉感。自学能力强,喜欢钻研新技术,敢于面对和克服困难。熟练使用spring+stru…

    2026年2月23日
    7
  • ConcurrentSkipListMap学习笔记

    ConcurrentSkipListMap学习笔记JDK 版本 AdoptOpenJDK 0 10 91 基本概念 ConcurrentSk 是在 JDK1 6 中新增的 为了对高并发场景下的有序 Map 提供更好的支持 它有几个特点 高并发场景 key 是有序的添加 删除 查找操作都是基于跳表结构 SkipList 实现的 2 跳表 SkipList 跳表 SkipList 是一种类似于链表的数据结构 其查询 插入 删除的时间复杂度都是 O logn 在传统的单链表结构中 查找某个元素需要从链表的头部按顺序遍历

    2026年3月16日
    1
  • HTTP.UTF_8过时

    HTTP.UTF_8过时

    2021年5月16日
    160

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号