• 多线程同步工具ReentrantLock CountDownLatch CyclicBarrier Semaphore join


    ReentrantLock、CountDownLatch 、Semaphore三者底层都是AbstractQueuedSynchronizer,逻辑都是先获取通行许可,成功了执行接下来的代码,失败了挂起;另外就是要在合适的时候唤醒其他线程。

    对照上面的流程

    ReentrantLock获取通行许可是lock---acquire---tryAcquire方法用cas把state从0变到1,唤醒其他线程是unlock---release---tryRelease方法中,同时把state从1变到0(暂时忽略可重入的情况)。

    CountDownLatch 获取通行许可是await---acquireSharedInterruptibly---tryAcquireShared 检测state是否为0,唤醒其他线程是countDown---releaseShared---tryReleaseShared判断state是否大于0,是的话state减一,如果减一之后恰好为0,则唤醒其他线程。

    Semaphore获取资源是acquire---acquireSharedInterruptibly---tryAcquireShared 检测state是否大于0,是的话减去1并获取通行许可;唤醒线程是在release---releaseShared---tryReleaseShared把state加1,并唤醒其他线程。

    CyclicBarrier:和上面说的三者不同,用的是ReentrantLock的await和singalAll,获取通行许可是用await---dowait---用ReentrantLock加锁并让count减一,如果count为0,则获取许可,同时执行回调方法,并唤醒等待队列,而且会开启下一轮等待,如果不为0,用condition.await挂起到等待队列;所以CyclicBarrier是把获取许可之后会同时唤醒其他线程,可以循环的await多次。

    再说说join(): Thread类的同步方法,假设代码:Thread a = new Thread(); a.start(); a.join(); 这段代码在线程b中执行,b执行到a.join的时候,进入同步锁,无限循环中,判断a是否存活,如果a存活,调用a.wait()挂起线程b。当a线程执行完或者异常退出的时候,JVM会调用a.notifyAll方法唤醒b,b被唤醒后,此时a已经退出,b向下执行完a.join方法。

    ps:想到这里,突然发现既然CountDownLatch是一次性的,那么RocketMQ源码在consumer rebalance的时候,是一个countDownLatch在循环的等待wakeUp也就是重新负载均衡的信号,这是为什么呢?进去一看,原来是rocketMQ重新写了一个,增加了reset也就是重新设置state的方法,但是这个state按道理来讲是不能随便重新设置的,有线程安全问题的,重写的countDownLatch用了hasNotified这个Atomic的变量进行了隔离来解决这个问题。

  • 相关阅读:
    Nginx之keepalived高可用工具
    Linux安装Nginx
    Nginx解决服务器宕机问题
    前端知识小札
    SQL入门(3):定义约束/断言assertion/触发器trigger
    SQL入门(2): Oracle内置函数-字符/数值/日期/转换/NVL/分析函数与窗口函数/case_decode
    Excel VBA入门(8): 快捷键/内置常量/代码调试/错误处理/代码优化
    小学生都看得懂的C语言入门(6): 字符串
    小学生都看得懂的C语言入门(5): 指针
    小学生都看得懂的C语言入门(4): 数组与函数
  • 原文地址:https://www.cnblogs.com/chuliang/p/13225487.html
Copyright © 2020-2023  润新知