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的变量进行了隔离来解决这个问题。

  • 相关阅读:
    Hibernate笔记——(ONE TO ONE)一对一
    Hibernate笔记——第一个简单实例
    Hibernate笔记——Hibernate介绍和初次环境配置
    JavaWeb笔记——ajax异步请求
    Spring笔记——Spring+JDBC组合开发
    Spring笔记——使用Spring进行面向切面(AOP)编程
    Spring笔记——依赖注入
    Java笔记——面向切面编程(AOP模式)
    Spring笔记——Spring框架简介和初次框架配置
    Java产生随机数
  • 原文地址:https://www.cnblogs.com/chuliang/p/13225487.html
Copyright © 2011-2022 走看看