本文共 3231 字,大约阅读时间需要 10 分钟。
如果线程持有锁而延迟,会导致其他的线程的等待。
高优先级的线程阻塞,而低优先级的线程持有锁造成 优先级反转(priority inversion)。
如果持有锁的线程被永久地阻塞,所有等待这个锁的线程就无法执行下去,造成 死锁(dead lock)。
比较并交换CAS:我认为V的值应该是A,如果是,那么将V的值更新为B,否则不修改并告诉V的值实际为多少
非阻塞的计数器:
@ ThreadSafepublic class CasCounter { private SimulatedCAS value ; public int getValue(){ return value .get(); } public int increment(){ int v; do { v = value .get(); } while (v != value .compareAndSwap(v, v + 1)); return v + 1; }}
原子变量比锁的粒度更细,量级更轻,并且对于在多处理器系统上实现高性能的并发代码来说是非常关键的
原子变量类相当于一种泛化的volatile变量,能够支持原子的和有条件的读-改-写操作
12个原子变量类,分为4组:标量类、更新器类、数组类、复合变量类
volatile类型的数组仅在数组引用上具有volatile语义,而在其元素上则没有
基本类型的包装类是不可修改的,而原子变量类是可修改的
使用ReentrantLock、AtomicInteger、ThreadLocal比较,通常情况下效率排序是ThreadLocal > AtomicInteger > ReentrantLock。
非阻塞算法的特性:某项工作具有不确定性,必须重新执行
非阻塞的栈
//使用 Treiber 算法的非阻塞堆栈@ThreadSafepublic class ConcurrentStack{ AtomicReference > top = new AtomicReference >(); public void push(E item) { Node newHead = new Node (item); Node oldHead; do { oldHead = top.get(); newHead.next = oldHead; } while (!top.compareAndSet(oldHead, newHead)); } public E pop() { Node oldHead; Node newHead; do { oldHead = top.get(); if (oldHead == null) return null; newHead = oldHead.next; } while (!top.compareAndSet(oldHead, newHead)); return oldHead.item; } private static class Node { public final E item; public Node next; public Node(E item) { this.item = item; } }}
@ThreadSafepublic class LinkedQueue{ private static class Node { final E item; final AtomicReference > next; public Node(E item, LinkedQueue.Node next) { this.item = item; this.next = new AtomicReference >(next); } } private final LinkedQueue.Node dummy = new LinkedQueue.Node (null, null); private final AtomicReference > head = new AtomicReference >(dummy); private final AtomicReference > tail = new AtomicReference >(dummy); public boolean put(E item) { LinkedQueue.Node newNode = new LinkedQueue.Node (item, null); while (true) { LinkedQueue.Node curTail = tail.get(); LinkedQueue.Node tailNext = curTail.next.get(); if (curTail == tail.get()) { if (tailNext != null) { // A // 队列处于中间状态,推进尾节点 tail.compareAndSet(curTail, tailNext); // B } else { // 处于稳定状态,尝试插入新节点 if (curTail.next.compareAndSet(null, newNode)) { // C // 插入操作成功,尝试推进尾节点 tail.compareAndSet(curTail, newNode); // D return true; } } } } }}
原子的域更新器:
ABA问题
ABA问题是一种异常现象:如果在算法中的节点可以被循环使用,那么在使用“比较并交换”指令时就可能出现这种问题(主要在没有垃圾回收机制的环境中)。在CAS操作中将判断“V的值是否仍然是A?”,并且如果是的话就继续执行更新操作。在大多数情况下,这种判断是完全足够的。然而,有时候还需要知道“自从上次看到V的值为A以来,这个值是否发生了变化?” 在某些算法中,如果V的值首先由A变成B,再由B变成A,那么仍然被认为是发生了变化,并需要重新执行算法中的某些步骤。
有一个相对简单的解决方案:不是更新某个引用的值,而是更新两个值,包括一个引用和一个版本号。即使这个值由A变成B,然后又变成A,版本号也将是不同的。
转载地址:http://dmkvb.baihongyu.com/