看了下网上关于链表的无锁操作,写的不清楚,遂自己整理一部分,主要使用concurrent并发包的CAS操作。

1. 链表尾部插入

待插入的节点为:cur

尾节点:pred

基本插入方法:

do{

  pred = find_tail();              //重新找尾节点

}(! pred.next.compareAndSet(NULL, cur))  //pred.next 是否为NULL,是则将其指向cur,不是则有新的节点插入

这种插入方法是不带标记的,如果不涉及链表删除这个方法是可行的。

但是如果有删除操作,pred节点可能会被删除,所以我们需要再加入一个标记位判断pred是否被删除(false 未删除)

do{

  pred = find_tail();              

}(! pred.next.compareAndSet(NULL, cur, false, false));  //检查pred.next是被否标记为false,并标记为false

因为我们插入是对pred.next进行CAS操作,所以虽然要判断pred是否被删除,我们却只能看它的next域的标记,所以在删除的时候要和这里配合置next位为true让本次添加不成功

注意这里的next的置位与否不是next节点的,是pred本身的,因为只能从pred自己看到是否被删除,所以节点的数据结构不包含flag,节点的next域包含flag,这种结构具体参考AtomicMarkableReference

这里如果先判断pred是否为false是不行的,所有操作必须在CAS中完成,因为判断的一瞬间是OK的但是不代表执行CAS的时候也是OK的

(TIP:因为是队尾,next域是NULL,但是仍然含有标记位,每个新node尾节点添加的时候都是node.next = new AtomicMarkableReference<Node>(null,false))

2. 链表删除节点

待删除的节点为:cur

do{

  succ = cur.next;        //重新找next节点

  if (cur.next == true) break;   //有线程已经将其逻辑删除

  pred = pred(cur);       //找pred节点

  flag1 = cur.next.compareAndSet(succ, succ, false, true);  //第一个CAS将cur.next置为true,防止添加操作和重复删除操作

  if (! flag1) continue;

  flag2 = pred.next.compareAndSet(cur, succ, false, false);  //第二个CAS将pred.next指向succ,并将succ的为置为false

  if(! flag2) continue;

}(0);

这里两次CAS操作,第一次置位,也就是所谓的逻辑删除,和添加节点相呼应,这里标记完了之后在第二个CAS执行前,往本节点之后的添加都不成功

本次CAS失败说明有其它线程的删除操作或CAS之前有往cur的next有添加操作(succ改变),返回再次尝试

第二次则将原来指向cur的pred.next指向succ,进行物理删除,这里succ已经不能改变了,因为第一次CAS成功之后next置位其他线程既不能添加也不能删除

但是pred可以被删除,pred被删除之后导致pred.next置位,这次CAS失败。

这里第二次CAS操作可能其他地方也有相同的代码,如果本线程在第一次CAS调用完后阻塞,可以让其他线程看到这个标记后帮忙进行节点删除和清置位,这也是wait free的设计的核心思想

3. 链表某节点插入

实现原理相同,不多赘述,一定要注意和删除的判断过程是保证自洽的。

链表的无锁操作 (JAVA)的更多相关文章

  1. Atitit。Cas机制 软件开发 编程语言 无锁机制 java c# php

    Atitit.Cas机制 软件开发 编程语言 无锁机制 java c# php 1. 为什么需要无锁操作1 2. 硬件支持 cas  atomic2 3. 无锁编程(Lock-Free)就是在某些应用 ...

  2. 聊聊高并发(三十二)实现一个基于链表的无锁Set集合

    Set表示一种没有反复元素的集合类,在JDK里面有HashSet的实现,底层是基于HashMap来实现的.这里实现一个简化版本号的Set,有下面约束: 1. 基于链表实现.链表节点依照对象的hashC ...

  3. 无锁同步-JAVA之Volatile、Atomic和CAS

    1.概要 本文是无锁同步系列文章的第二篇,主要探讨JAVA中的原子操作,以及如何进行无锁同步. 关于JAVA中的原子操作,我们很容易想到的是Volatile变量.java.util.concurren ...

  4. CAS无锁操作

    https://coolshell.cn/articles/8239.html 主要讲的是<Implementing Lock-Free Queues>的论点,具体直接看论文最好.这里总结 ...

  5. 【Java并发编程】9、非阻塞同步算法与CAS(Compare and Swap)无锁算法

    转自:http://www.cnblogs.com/Mainz/p/3546347.html?utm_source=tuicool&utm_medium=referral 锁(lock)的代价 ...

  6. (转载)java高并发:CAS无锁原理及广泛应用

    java高并发:CAS无锁原理及广泛应用   版权声明:本文为博主原创文章,未经博主允许不得转载,转载请注明出处. 博主博客地址是 http://blog.csdn.net/liubenlong007 ...

  7. 非阻塞同步算法与CAS(Compare and Swap)无锁算法

    锁(lock)的代价 锁是用来做并发最简单的方式,当然其代价也是最高的.内核态的锁的时候需要操作系统进行一次上下文切换,加锁.释放锁会导致比较多的上下文切换和调度延时,等待锁的线程会被挂起直至锁释放. ...

  8. boost 无锁队列

    一哥们翻译的boost的无锁队列的官方文档 原文地址:http://blog.csdn.net/great3779/article/details/8765103 Boost_1_53_0终于迎来了久 ...

  9. DIOCP开源项目-Delphi高性能无锁队列(lock-free)

    最近想在DIOCP中加入任务调度线程,DIOCP的工作线程作为生产者(producer)将接受到的数据对象,投递到任务调度线程中,然后统一进行分配.然而这一切都需要一个队列, 这几天都在关注无锁队列. ...

随机推荐

  1. java循环遍历类属性 get 和set值方法

    //遍历sqspb类 成员为String类型 属性为空的全部替换为"/"Field[] fields = sqspb.getClass().getDeclaredFields(); ...

  2. CentOS7配置php7.0支持redis

    配置之前应该是环境已经搭好了,phpinfo的页面可以加载出来. 使用git clone下载git上的phpredis扩展包 [root@VM_103_117_centos ]#git clone   ...

  3. requests-模拟登陆

    import requests requests.get('http://httpbin.org/cookies/set/number/123456') response = requests.get ...

  4. jquery中substring,substr,split的用法

    一.substring 方法 返回位于 String 对象中指定位置的子字符串. strVariable.substring(start, end) "String Literal" ...

  5. Web标准的简单理解 不同内核浏览器的差异以及浏览器渲染简介(转)

    Web标准是一系列标准的集合.这些标准大概分三方面:结构.表现和行为.结构化主要有HTML, XHTML和XML,表现主要有CSS,行为标准主要包括对象模型,如 W3C DOM.ECMAScript等 ...

  6. 【Markdown 语法】

    Markdown 语法 摘抄自MWEB Markdown 的设计哲学 Markdown 的目標是實現「易讀易寫」. 不過最需要強調的便是它的可讀性.一份使用 Markdown 格式撰寫的文件應該可以直 ...

  7. [LeetCode] Pour Water 倒水

    We are given an elevation map, heights[i] representing the height of the terrain at that index. The ...

  8. 机器学习基石:06 Theory of Generalization

    若H的断点为k,即k个数据点不能被H给shatter,那么k+1个数据点也不能被H给shatter,即k+1也是H的断点. 如果给定的样本数N是大于等于k的,易得mH(N)<2N,且随着N的增大 ...

  9. 【BZOJ3233】【tyvj1729】文艺平衡树

    原题传送门 解题思路:裸平衡树操作,支持区间翻转即可,这里写了无旋treap. 其实平衡树的区间操作就和线段树差不多,你用个标记搞一下就好了,,,,, #include <stdio.h> ...

  10. empty()和size()的优劣

    通常下面代码: if(c.size() == 0) if(c.empty()) 我们会觉得它们是是等价的. 为何empty()比较好? 主要是他们之间的效率有一定差距: empty对任意的容器都是常数 ...