CLH是一种基于单向链表(隐式创建)的高性能、公平的自旋锁,申请加锁的线程只需要在其前驱节点的本地变量上自旋,从而极大地减少了不必要的处理器缓存同步的次数,降低了总线和内存的开销。
public class CLHLock {
class Node {
//false代表没人占用锁
volatile boolean locked = false;
}
//指向最后加入的线程
final AtomicReference<Node> tail = new AtomicReference<>(new Node());
//使用ThreadLocal保证每个线程副本内都有一个Node对象
final ThreadLocal<Node> current;
public CLHLock() {
//初始化当前节点的node
current = new ThreadLocal<Node>() {
@Override
protected Node initialValue() {
return new Node();
}
};
}
public void lock() throws InterruptedException {
//得到当前线程的Node节点
Node own = current.get();
//修改为true,代表当前线程需要获取锁
own.locked = true;
//设置当前线程去注册锁,注意在多线程下环境下,这个
//方法仍然能保持原子性,,并返回上一次的加锁节点(前驱节点)
Node preNode = tail.getAndSet(own);
//在前驱节点上自旋
while (preNode.locked) {
System.out.println(Thread.currentThread().getName() + " 开始自旋.... ");
Thread.sleep(2000);
}
}
public void unlock() {
//当前线程如果释放锁,只要将占用状态改为false即可
//因为其他的线程会轮询自己,所以volatile布尔变量改变之后
//会保证下一个线程能立即看到变化,从而得到锁
current.get().locked = false;
}
public static void main(String[] args) throws InterruptedException {
CLHLock lock = new CLHLock();
Runnable runnable = new Runnable() {
@Override
public void run() {
try {
lock.lock();
System.out.println(Thread.currentThread().getName() + " 获得锁 ");
//前驱释放,do own work
Thread.sleep(5000);
System.out.println(Thread.currentThread().getName() + " 释放锁 ");
lock.unlock();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
Thread t1 = new Thread(runnable, "线程1");
Thread t2 = new Thread(runnable, "线程2");
Thread t3 = new Thread(runnable, "线程3");
t1.start();
t2.start();
t3.start();
}
}
java的juc中的aqs
队列头节点释放锁之后,会唤醒下一个节点的线程
下一个节点检查前一个节点是头节点,则获取锁成功,否则线程挂起
在获取同步状态时,同步器维护一个同步队列,获取状态失败的线程都会被加入到队列中并在队列中进行自旋;移出队列(或停止自旋)的条件是前驱节点为头节点且成功获取了同步状态。在释放同步状态时,同步器调用tryRelease(int arg)方法释放同步状态,然后唤醒头节点的后继节点
// 入队列
private Node enq(final Node node) {
for (;;) {
Node t = tail;
if (t == null) { // Must initialize
// 如果head是null,设置为new Node()
if (compareAndSetHead(new Node()))
tail = head;
} else {
node.prev = t;
if (compareAndSetTail(t, node)) {
t.next = node;
return t;
}
}
}
}
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
final Node p = node.predecessor();
// 如果前节点是头节点并获取同步状态成功则获得锁
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
failed = false;
return interrupted;
}
// 获取失败则阻塞
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
https://cloud.tencent.com/developer/article/1187386