《Java并发编程实战》笔记-非阻塞算法
如果在某种算法中,一个线程的失败或挂起不会导致其他线程也失败和挂起,那么这种算法就被称为非阻塞算法。如果在算法的每个步骤中都存在某个线程能够执行下去,那么这种算法也被称为无锁(Lock-Free)算法。如果在算法中仅将CAS用于协调线程之间的操作,并且能正确地实现,那么它既是一种无阻塞算法,又是一种无锁算法。
创建非阻塞算法的关键在于,找出如何将原子修改的范围缩小到单个变量上,同时还要维护数据的一致性。
非阻塞算法的所有特性:某项工作的完成具有不确定性,必须重新执行。
复杂数据结构的非阻塞算法,如非阻塞链接队列,因为它必须支持对头节点和尾节点的快速访问,因此它需要单独维护头指针和尾指针。插入新元素时需要采用两个原子操作更新当前最后元素指针和尾指针,这会使队列处于不一致状态。我们需要使用一些技巧,第一是,即使在一个包含多个步骤的更新操作中,也要确保数据结构总是处于一致状态。第二是,如果当B到达时发现A正在修改数据结构,那么在数据结构中就应该有足够的信息,使得B能完成A的更新操作。
Michael-Scott(Michael and Scott,1996)非阻塞算法中的插入算法
package net.jcip.examples; import java.util.concurrent.atomic.*; import net.jcip.annotations.*; /**
* LinkedQueue
* <p/>
* Insertion in the Michael-Scott nonblocking queue algorithm
*
* @author Brian Goetz and Tim Peierls
*/
@ThreadSafe
public class LinkedQueue <E> { private static class Node <E> {
final E item;
final AtomicReference<LinkedQueue.Node<E>> next; public Node(E item, LinkedQueue.Node<E> next) {
this.item = item;
this.next = new AtomicReference<LinkedQueue.Node<E>>(next);
}
} private final LinkedQueue.Node<E> dummy = new LinkedQueue.Node<E>(null, null);
private final AtomicReference<LinkedQueue.Node<E>> head
= new AtomicReference<LinkedQueue.Node<E>>(dummy);
private final AtomicReference<LinkedQueue.Node<E>> tail
= new AtomicReference<LinkedQueue.Node<E>>(dummy); public boolean put(E item) {
LinkedQueue.Node<E> newNode = new LinkedQueue.Node<E>(item, null);
while (true) {
LinkedQueue.Node<E> curTail = tail.get();
LinkedQueue.Node<E> tailNext = curTail.next.get();
if (curTail == tail.get()) {
if (tailNext != null) {
// Queue in intermediate state, advance tail
tail.compareAndSet(curTail, tailNext);
} else {
// In quiescent state, try inserting new node
if (curTail.next.compareAndSet(null, newNode)) {
// Insertion succeeded, try advancing tail
tail.compareAndSet(curTail, newNode);
return true;
}
}
}
}
}
}
ABA问题,在某些算法中,如果V的值首先由A变成B,再由B变成A,那么仍然被认为是发生了变化,并需要重新执行算法中的某些步骤。Java类库提供AtomicStampedReferencet和AtomicMarkableReference处理ABA问题。AtomicStampedReferencet将更新一个“对象-引用”二元组,通过在引用上加上“版本号”,从而避免ABA问题。AtomicMarkableReference将更新一个“对象引用-布尔值”二元组,在某些算法中将通过这种二元组使节点保存在链表中同时又将其标记为“已删除的节点”。
《Java并发编程实战》笔记-非阻塞算法的更多相关文章
- Java并发编程实战.笔记十一(非阻塞同步机制)
关于非阻塞算法CAS. 比较并交换CAS:CAS包含了3个操作数---需要读写的内存位置V,进行比较的值A和拟写入的新值B.当且仅当V的值等于A时,CAS才会通过原子的方式用新值B来更新V的值,否则不 ...
- 29、Java并发性和多线程-非阻塞算法
以下内容转自http://ifeve.com/non-blocking-algorithms/: 在并发上下文中,非阻塞算法是一种允许线程在阻塞其他线程的情况下访问共享状态的算法.在绝大多数项目中,在 ...
- 多线程-java并发编程实战笔记
线程安全性 编写线程安全的代码实质上就是管理对状态的访问,而且通常都是共享的,可变的状态. 一个对象的状态就是他的数据,存储在状态变量中,比如实例域或静态域.所谓共享是指一个对象可以被多个线程访问:所 ...
- Java并发编程实战笔记—— 并发编程1
1.如何创建并运行java线程 创建一个线程可以继承java的Thread类,或者实现Runnabe接口. public class thread { static class MyThread1 e ...
- Java并发编程实战笔记
如果当多个线程访问同一个可变的状态变量时没有使用合适的同步,那么程序就会出现错误.有三种方式可以修复这个问题: i.不在线程之间共享该状态变量 ii.将状态变量修改为不可变的变量 iii.在访问状态变 ...
- java并发编程实战笔记---(第五章)基础构建模块
. 5.1同步容器类 1.同步容器类的问题 复合操作,加容器内置锁 2.迭代器与concurrentModificationException 迭代容器用iterator, 迭代过程中,如果有其他线程 ...
- java并发编程实战笔记---(第三章)对象的共享
3.1 可见性 synchronized 不仅实现了原子性操作或者确定了临界区,而且确保内存可见性. *****必须在同步中才能保证:当一个线程修改了对象状态之后,另一个线程可以看到发生的状态变化. ...
- java并发编程实战笔记---(第四章)对象的组合
4.1设计线程安全的类 包含三个基本要素: 1.找出构成对象状态的所有变量 2.找出约束状态变量的不变性条件 2.简历对象状态的并发访问管理策略 对象的状态: 域 基本类型所有域, 引用类型包括被引用 ...
- Java并发编程实战笔记—— 并发编程4
1.同步容器类 同步容器类都是线程安全的,但在某些情况下可能需要额外的客户端加锁保护复合操作. 容器上常见的复合操作包括但不限于:迭代(反复访问数据,直到遍历完容器中所有的元素为止).跳转(根据指定顺 ...
- Java并发编程实战笔记—— 并发编程2
1.ThreadLocal Java中的ThreadLocal类可以让你创建的变量只被同一个线程进行读和写操作.因此,尽管有两个线程同时执行一段相同的代码,而且这段代码又有一个指向同一个ThreadL ...
随机推荐
- lesson5rnns-fastai
32min 如何确定embedding个数即嵌入矩阵容量?:不确定:与文本的字数关系不大,关键是语言的复杂度和需要解决的问题类型 embedding的效果要比one hot编码的效果好
- mariaDB的安装 apache的安装
1.mariaDB的安装: 下载安装包: wget -c https://downloads.mariadb.com/MariaDB/mariadb-10.3.6/bintar-linux-glibc ...
- java exception 01
问题:java.util.concurrentmodificationexception 背景:java thread 网上找到的出现的例子如下(项目中真实的code不便给出) public clas ...
- software download
Develop Sourceinsight 3.50.0066 http://pan.baidu.com 这个版本支持输入文件名的一部分来查找文件,而不像3.50.0029必须输入完整的文件名 VFP ...
- 将数组A中的内容和数组B中的内容进行交换。(数组一样大)
将两个数组中的内容相互交换,必须是两个数组的内容一样大小. 思路: 结合两个整型变量之间的交换,同样可以用于内容一样大的数组.用异或关系相互交换. #include<stdio.h> in ...
- 关于package.json
1.dependencies和devDependenceis npm install packageName --save配置到dependencies,代表代码运行时所需要的插件(比如jquery, ...
- DOM Access and Manipulation JS 操纵DOM
JS 操纵DOM 有两种很简单的方式: 如果知道ID 的情况下. 我们可以使用 document.getElementById 我们还可以使用 document.getElementById(&quo ...
- HI3516EV100 RTMP添加音频
1.先试试只发音频 失败 2.保存音频,发送视频,成功
- Java 反射基础
1.反射概念: Java运行时,动态获得类的信息以及动态调用对象的方法的功能. 在运行时判断任意一个对象所属的类 在运行时构造任意一个类的对象 在运行时判断任意一个类所具有的成员变量和方法 在运行时调 ...
- 解决openwrt中文界面异常
openwrt的luci以中文字体显示时,出现以下异常情况: 是因为该固件编译了其他的luci application,我是编译了meshwizard. 可作如下修改: scp登陆打开/usr/lib ...