本篇内容介绍了“java的CLH队列锁是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!
CLH队列锁是一种自旋锁,提供先来先服务的公平性。
CLH基于链表实现。线程只是在不断的自旋,不断地轮询前驱节点的状态,如果前驱节点释放了锁,那么线程结束自旋。
对于持锁时间很短的场景,比之间把线程阻塞住具有较高的性能,并能可以保持一定的公平性。
还有搭配自旋次数做深入的优化,使得使用场景更广,性能更好。
对于特定应用场景,使用这种锁可以提高性能,是一种锁的优化方向。
核心理念就是,不要阻塞线程,用循环来替换。
一种LCH参考实现
public class ClhSpinLock implements Lock {
/**
* 前驱节点 每个线程
*/
private final ThreadLocal<Node> prev = ThreadLocal.withInitial(Node::new);
/**
* 当前节点
*/
private final ThreadLocal<Node> currentThreadNode = ThreadLocal.withInitial(Node::new);
/**
* 指向队列末尾节点
* <p>
* 值得注意 这个节点的默认值是false 也就是说 如果前驱节点是这个默认的节点 那么它是不会起到锁的作用
* 即 第一个线程进来 执行lock()操作之后 立即返回
* <p>
* 还有所有就是 所有的线程都共享这个tail引用
* 链表推进是依靠这个共享的tail
*/
private final AtomicReference<Node> tail = new AtomicReference<>(new Node());
public ClhSpinLock() {
}
/**
* 1.初始状态 tail指向一个node(head)节点
* +------+
* | head | <---- tail
* +------+
* <p>
* 2.lock-thread加入等待队列: tail指向新的Node,同时Prev指向tail之前指向的节点
* +----------+
* | Thread-A |
* | := Node | <---- tail
* | := Prev | -----> +------+
* +----------+ | head |
* +------+
* <p>
* +----------+ +----------+
* | Thread-B | | Thread-A |
* tail ----> | := Node | --> | := Node |
* | := Prev | ----| | := Prev | -----> +------+
* +----------+ +----------+ | head |
* +------+
* 3.寻找当前node的prev-node然后开始自旋
*/
@Override
public void lock() {
// 值得注意的细节
// 如果是第一个线程进来
// 那么pred.locked是false 所以这个线程调用lock之后就直接返回了
// 第二个线程进来之后 它的pred就是第一个线程的
// 之后的线程以此类推
final Node currentThreadNode = this.currentThreadNode.get();
currentThreadNode.locked = true;
// 所有线程都通过这个tail的不断变换去推进
final Node prev = this.tail.getAndSet(currentThreadNode);
// 这个只是满足每个线程自己prev的设置 其实是可以省略掉的
this.prev.set(prev);
// 自旋
while (prev.locked) {
}
}
@Override
public void unlock() {
final Node node = this.currentThreadNode.get();
node.locked = false;
this.currentThreadNode.set(this.prev.get());
}
@Override
public void lockInterruptibly() throws InterruptedException {
}
@Override
public boolean tryLock() {
return false;
}
@Override
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
return false;
}
@Override
public Condition newCondition() {
return null;
}
private static class Node {
private volatile boolean locked;
}
}
相关的测试代码
public class ClhSpinLockTest {
private static int count = 0;
private static void testLock(Lock lock) {
try {
lock.lock();
System.out.println("任务启动线程名称:" + Thread.currentThread().getName() + " 任务开始时统计数:" + count + " 任务执行时间:" + System.currentTimeMillis());
for (int i = 0; i < 100; i++) {
count++;
}
System.out.println("任务启动线程名称:" + Thread.currentThread().getName() + " 任务结束时统计数:" + count);
} finally {
lock.unlock();
}
}
public static void main(String[] args) {
int workerThreadNums = 5;
// 这个锁是需要每个相关线程都需要持有的
final ClhSpinLock clhSpinLock = new ClhSpinLock();
// 这个是一个栅栏 目的是等到所有线程都执行完 看结果
final CyclicBarrier cyclicBarrier = new CyclicBarrier(workerThreadNums, () -> System.out.println("最终结果:" + count));
for (int i = 0; i < workerThreadNums; i++) {
new Thread(() -> {
testLock(clhSpinLock);
try {
cyclicBarrier.await();
} catch (Exception e) {
e.printStackTrace();
}
}).start();
}
}
}
空间复杂度低
在不同CPU结构体系下,性能是不同的。
“java的CLH队列锁是什么”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注亿速云网站,小编将为大家输出更多高质量的实用文章!
亿速云「云服务器」,即开即用、新一代英特尔至强铂金CPU、三副本存储NVMe SSD云盘,价格低至29元/月。点击查看>>
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。
原文链接:https://my.oschina.net/snakevash123/blog/3119371