zoukankan      html  css  js  c++  java
  • 多线程同步工具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的变量进行了隔离来解决这个问题。

  • 相关阅读:
    Window如何查看cpu核数,更改CPU开启的核数?
    Mysql5.6.47开放远程访问(修改远程访问密码)
    CentOS7.6新增或修改SSH端口号的步骤
    虚拟机下安装Centos设置静态ip,并通过桥接连接
    windows下安装mysql5.6.47版本
    微软官方安装介质Windows10系统安装教程
    【测试编码URI的函数】
    【JavaScript函数】
    【JavaScript运算符与表达式】
    【JavaScript声明变量的规则】
  • 原文地址:https://www.cnblogs.com/chuliang/p/13225487.html
Copyright © 2011-2022 走看看