您好,登录后才能下订单哦!
密码登录
登录注册
点击 登录注册 即表示同意《亿速云用户服务条款》
本篇内容介绍了“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队列锁是什么”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注亿速云网站,小编将为大家输出更多高质量的实用文章!
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。