aqs clh java_浅谈Java AQS实现——CLH锁

CLH锁是一种基于链表的公平自旋锁,其核心在于线程在其前驱节点上自旋等待锁的释放。AQS(AbstractQueuedSynchronizer)作为Java并发包中的核心组件,其设计灵感来源于CLH锁。在AQS中,线程获取锁失败会进入等待队列,类似于CLH锁的自旋等待。本文通过代码展示了CLHLock的实现,并分析了其工作原理,为理解AQS提供基础。
摘要由CSDN通过智能技术生成

在AQS源码的注释中提到AQS是CLH锁的一个变种,所以了解一下CLH锁有助于我们学习AQS。CLH锁是基于链表的、公平的的自旋锁。
这里直接贴代码(代码来自《多处理器编程的艺术》机械工业出版社)

// 这里只实现了Lock接口的部分方法

public class CLHLock implements Lock {

AtomicReference tail = new AtomicReference(new QNode());

ThreadLocal myPred;

ThreadLocal myNode;

public CLHLock() {

// 队列有一个默认的头节点

tail = new AtomicReference(new QNode());

myNode = new ThreadLocal() {

@Override

protected QNode initialValue() {

return new QNode();

}

};

myPred = new ThreadLocal() {

@Override

protected QNode initialValue() {

return null;

}

};

}

@Override

public void Lock() {

QNode qnode = myNode.get();

qnode.locked = true;

// 原子的进入队列

QNode pred = tail.getAndSet(qnode);

myPred.set(pred);

// 在前驱节点的locked字段上自旋,第一个线程则会检测默认的头节点的locked的值

while (pred.locked) {

}

}

@Override

public void Unlock() {

QNode qnode = myNode.get();

// 放弃锁,后驱节点可以继续

qnode.locked = false;

// 这个有点绕,把当前线程的myNode引用设置成队列的头节点,前线程的myNode的原引用则变成队列的头结点。前线程的myNode则会从队列中脱离。

myNode.set(myPred.get());

}

// 在书中没有给出QNode的定义

private class QNode {

// 不知道作者的原意是在这里使用volatile来实现锁的内存语义还是通过其他的方式。

public volatile boolean locked = false;

}

}

CLH锁的核心在于线程在他对应节点的前驱节点上自旋,等待前驱节点放弃锁的通知,CLH锁在NUMA系统结构下表现差也是因为此,AQS的实现与CLH锁相似的地方也在于此。在AQS中线程获取失败会进入等待队列,阻塞并等待前驱节点对应线程的唤醒。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值