这篇博客主要是做为 AbstractQueuedSynchronizer 的背景知识介绍;平时接触也很是的少,若是你不感兴趣能够跳过;可是了解一下能更加的清楚 AQS 的设计思路;java
一般状况下解决多线程共享资源逻辑一致性问题有两种方式:node
对于这两种方式没有优劣之分,只有是否适合当前的场景;具体的对比就不在继续深刻了,若是你很感兴趣能够查看 《多处理器编程的艺术》 提取码:rznn ;web
可是若是竞争很是激烈的时候,使用自旋锁就会产生一些额外的问题:编程
解决这些问题其中的一种办法就是使用队列锁,简单来说就是让这些线程排队获取;下面咱们介绍经常使用的两种,即 CLH 锁 和 MCS 锁;多线程
CLH 是 Craig、Landin 和 Hagersten 三位做者的缩写,具体内容在 《Building FIFO and Priority-Queuing Spin Locks from Atomic Swap》 论文中有详细介绍,你们能够自行查看;咱们 JDK 中 java.util.concurrent.locks.AbstractQueuedSynchronizer
就是根据 CLH 锁的变种实现的;架构
简单实现:ide
public class CLH implements Lock { private final ThreadLocal<Node> preNode = ThreadLocal.withInitial(() -> null); private final ThreadLocal<Node> node = ThreadLocal.withInitial(Node::new); private final AtomicReference<Node> tail = new AtomicReference<>(new Node()); private static class Node { private volatile boolean locked; } @Override public void lock() { final Node node = this.node.get(); node.locked = true; Node pre = this.tail.getAndSet(node); this.preNode.set(pre); while (pre.locked) ; } @Override public void unlock() { final Node node = this.node.get(); node.locked = false; this.node.set(this.preNode.get()); } }
一样 MCS 是 John M. Mellor-Crummey 和 Michael L. Scott 名字的缩写,具体内容能够在 《Algorithms for Scalable Synchronization on Shared-Memory Multiprocessors》 论文中查看;测试
简单实现:ui
public class MCS implements Lock { private final ThreadLocal<Node> node = ThreadLocal.withInitial(Node::new); private final AtomicReference<Node> tail = new AtomicReference<>(); private static class Node { private volatile boolean locked = false; private volatile Node next = null; } @Override public void lock() { Node node = this.node.get(); node.locked = true; Node pre = tail.getAndSet(node); if (pre != null) { pre.next = node; while (node.locked) ; } } @Override public void unlock() { Node node = this.node.get(); if (node.next == null) { if (tail.compareAndSet(node, null)) { return; } while (node.next == null) ; } node.next.locked = false; node.next = null; } }