1.为什么使用CAS
因为大多数的同步操作,超过90%的情况是不会碰到互斥的情况的,即不会碰到需要同步的情况,悲观锁则认为一直需要同步,影响了性能,CAS从硬件和算法层面避免这超过90%的情况。
2.什么是CAS
CAS 全称Compare-and-Swap,广义上的讲是CAS重入算法和CAS硬件操作。它采用乐观锁的方式,即认为不需要加锁,如果有多线程在同一时间段对同一个变量或者引用的指针进行操作,CAS的原理是,不加锁,本地变量value_0,先保存变量value_0的副本value_0_copy到栈空间,然后申明一个期望值value_update,利用硬件的CAS指令支持(如果不支持,则采用CAS重入算法,原理同上一句的操作),比较新老值value_0_copy和value_0,如果发现老值和新获得的值做比较,如果变化了,说明别的线程对这个值有改变,则认为更新失败,返回,至于返回失败之后是否需要重新执行,需要使用者进行判断,例如ConcurrentLinkedQueue,如果更新失败,ConcurrentLinkedQueue会一直重试,直到成功,但是会存在ABA的问题,如果ABA问题不影响逻辑,对结果没有副作用,则不需要考虑,如果对结果有副作用,则需要考虑使用其它方式。
ConcurrentLinkedQueue offer的源码
public boolean offer(E e) {
final Node<E> newNode = newNode(Objects.requireNonNull(e));
for (Node<E> t = tail, p = t;;) {
Node<E> q = p.next;
if (q == null) {
// p is last node 这里,如果p的next是null,
//说明p是最后一个,即为尾部tail,如果不是,重入外面的循环
if (casNext(p, null, newNode)) {
// Successful CAS is the linearization point
// for e to become an element of this queue,
// and for newNode to become "live".
//因为p节点已经更新,t也需要更新,因为t正在指向更新前的节点,
//不过这里更新失败也无所谓,因为casNext已经成功添加了新的尾部节点,
//但是这里的目的我可能没理解透?
//是设计者太严谨了,不放过任何一个地方,
//即使本地的栈空间不需要的变量也要保证严谨?
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;
}
}
static <E> boolean casNext(Node<E> node, Node<E> cmp, Node<E> val) {
return U.compareAndSwapObject(node, NEXT, cmp, val);
}
private boolean casTail(Node<E> cmp, Node<E> val) {
return U.compareAndSwapObject(this, TAIL, cmp, val);
}
3.ABA问题的处理
AtomicStampedReference加入时间戳解决ABA问题,1A 2B 3A
4.JVM对synchronized锁的优化
经过Java版本不停的改进,之前的synchronized属于完全悲观锁,后面的性能提升主要作了如下优化,优先使用乐观锁,锁的信息动态改变当前锁的状态,主要记录了如下3种状态,0,1,2,乐观锁,轻量锁和重量锁,一般情况下,使用乐观锁,如果碰到需要同步的情况,+1,知道变化成重量锁的方式,当然,使用重量锁是一直最不理想的状态,说明真的有许多并发的情况需要处理,这可能出现在高并发的服务器,这就不是开头说道的90%的情况下都不需要同步。