常用并发工具类总结

JUC 下的常用并发工具类(锁和线程间通信工具类),主要包括 ReentrantLockReentrantReadWriteLockCountDownLatchCyclicBarrierSemaphoreExchanger

ReentrantLock 和 ReentrantReadWriteLock

ReentrantLock 是可重入独占锁,ReentrantReadWriteLock 是可重入读写锁。

ReentrantLock

ReentrantLock 支持公平和非公平锁两种模式,可以通过 new ReentrantLock(boolean fair) 构造方法来指定公平或非公平模式,默认为非公平模式。
注意,公平和非公平模式在这里主要指的是尝试获取锁的线程是否会在排到同步队列末尾之前尝试获取一遍锁

  • 如果在排到队尾之前会尝试获取一边锁,那么就是非公平模式,因为有可能在这一次尝试获取就直接得到了锁,等同于一个插队操作,所以是非公平锁
  • 如果是老老实实排到队尾,那么就是公平模式,因为不会存在插队操作

ReentrantLock 的公平与非公平模式,主要是靠其内部的两个 AQS 子类,FairSyncNonfairSync 来实现的。

RenntrantReadWriteLock

ReentrantReadWriteLock 是读写锁,其主要性质如下:

  • ReentrantReadWriteLock 内部有一个 Sync 对象,用于执行所有的同步机制

    • Sync 类继承了 AQS
    • Sync 类有一个公平锁实现 FairSync,和一个非公平锁实现 NonfairSync
    • Sync 类中 state 的含义为,高 16 位代表获取读锁的次数,低 16 位代表获取写锁的次数
  • 内部有一个 ReadLock 对象(读锁),有一个 WriteLock 对象(写锁)
    • 读锁和写锁实际上都是依赖于 Sync 对象来实现的
    • 基于 Sync 对象对于 state 的定义,读锁和写锁的获取次数上限都为 65535 (2^16-1
    • 读锁的加锁操作本质上是对 state 的高 16 位进行 +1 操作,释放锁本质上是对 state 的高 16 位进行 -1 操作
    • 写锁的加锁操作本质上是对 state 的低 16 位进行 +1 操作,释放锁本之上是对 state 的低 16 位进行 -1 操作
  • 操作顺序与互斥关系
    • 读读不互斥
    • 写写互斥
    • 读写互斥
    • 写读互斥
  • 读锁和写锁均可重入
  • 读锁不能升级为写锁(即持有读锁时去获取写锁)
    • 如果使用 writeLock().lock() 获取写锁会发生死锁
    • 如果使用 writeLock().tryLock(long timeout, Timeunit unit) 会在超时后返回
  • 写锁可以降级为读锁(即持有写锁时去获取读锁)
  • 读锁和写锁的加锁和释放锁的逻辑必须成对出现

Semaphore

Semaphore信号量的意思,主要用于限定临界资源同时能被多少个线程访问。主要特性:

  • 内部有一个 Sync 类继承了 AQS,是 AQS 共享模式的一种具体实现
  • Sync 类有一个公平锁实现 FairSync,和一个非公平锁实现 NonfairSync,由构造函数 public Semaphore(int permits, boolean fair) 来指定
    • 公平锁实现,当前线程获取不到许可时,将会进入队列等待
    • 非公平锁实现,当前线程将会一直(自旋)尝试获取许可
  • Sync 类中 state 的含义为 public Semaphore(int permits)permits 的数值(许可的数量
  • Sync 类的获取许可操作本质上是对 state-1 操作,释放许可操作本之上是对 state+1 操作

Exchanger

Exchanger交换器的意思,主要用于两个线程之间的数据交换。
注意在多个线程同时使用一个 Exchanger 对象进行数据交换的时候,交换结果可能是未知的。所以 Exchanger 适用于成对线程之间的数据通信。

CyclicBarrier

CyclicBarrier循环栅栏的意思,主要用于帮助多个线程同时达到某个等待点后再把这些线程唤醒。主要特性:

  • 主要的构造函数为 public CyclicBarrier(int parties)public CyclicBarrier(int parties, Runnable barrierAction)

    • parties 代表的是参与协作的线程数量
    • barrierAction 代表的是协作线程的数量等于 parties 时,将会执行的动作
  • CyclicBarrier 有一把内置的 ReentrantLock 锁,和由这把锁创建出来的一个 Condition 对象
  • 当调用 await() 方法时,首先会尝试获取锁,获取成功后当前需要等待的剩余协作线程数量 -1
    • 如果此时需要等待的剩余协作线程数量不为 0,即代表参与协作的线程数量还没有到达初始设定的数量,则调用 Condition 对象的 await() 方法,将当前线程阻塞在 Condition 对象的条件队列中
    • 如果此时需要等待的协作线程数量为 0,即代表参与协作的线程数量已经到达了初始设定的数量,则执行打开栅栏动作(调用 nextGeneration() 方法),(调用 Condition 对象的 singalAll() 方法)唤醒所有等待在 Condition 对象上的线程,唤醒完成后,重置栅栏到初始状态
  • 当调用 reset() 方法时,之前调用了 await() 方法的所有线程将会被唤醒,并抛出异常
  • 当某个线程调用了 await() 方法后被中断,那么 CyclicBarrier 会被设置成一个中断状态,此时需要调用 reset() 方法把 CyclicBarrier 对象重置成初始状态

总的来说 ,CyclicBarrier 是通过 AQS 的条件等待机制(ConditionObject)来实现的

CountDownLatch

CountDownLatch计数门闩的意思,主要用于在一组执行线程都到达某个等待点之后,再唤醒等待在这个门闩上的所有线程一个同步工具。

  • 内部有一个 Sync 类继承了 AQS,是 AQS 共享模式的一种具体实现
  • Sync 类中 state 的含义为 public CountDownLatch(int count)count 的数值(需要打开门闩的次数
  • 调用 countDown() 方法后(相当于尝试释放共享锁),将会使用 CAS + 自旋将 state 变量值 -1
  • 调用 await() 方法后(相当于尝试获取共享锁),首先会判断当前的 state 是否等于 0
    • 如果等于 0,则获取成功,将会立马返回
    • 如果不等于 0,则获取失败,当前线程将会被封装为共享节点放入到 AQS 同步队列中,并阻塞

CyclicBarrier 和 CountDownLatch 的异同

相同点:

  • 都是 JUC 包下的同步工具类
  • 都是 AQS 的应用实例
  • 都可以在指定数目个线程到达某个等待点后,执行一些动作

不同点:

  • 实现目标不同:

    • CyclicBarrier 是帮助多个协作线程最终都到达某个等待点后,再同时唤醒这些协作线程本身
    • CountDownLatch 是在多个执行线程最终都到达某个等待点后,再同时唤醒所有等待线程
  • 调用方式不同:
    • CyclicBarrier 调用 await() 方法后,如果此时的 count 值不为 0,那么将会阻塞自身,所以不能在同一时间连续调用
    • CountDownLatch 在调用 countDown() 方法后,不会阻塞自身,在同一时间可以连续调用
  • 阻塞、修改计数计数和通知的对象不一样:
    • CyclicBarrier 阻塞、修改计数和通知的对象都是执行 await() 方法的线程
    • CountDownLatch 阻塞和通知的是调用 await() 方法的线程,修改计数的对象是执行 countDown() 方法的线程
  • 实现方式不同:
    • CyclicBarrier 是基于 AQS 的条件等待机制来实现的
    • CountDownLatch 内部有一个 Sync 类直接继承了 AQS,是 AQS 共享机制的一种实现
  • 状态是否可重置:
    • CyclicBarrier 可以在到达计数条件后重置自身状态,可以重复使用;也可以主动调用 reset() 方法来重置自身状态
    • CountDownLatch 不能重置自身状态,不能重复使用
  • 计数条件到达后是否可以执行操作:
    • CyclicBarrier 可以调用 public CyclicBarrier(int parties, Runnable barrierAction) 中传入计数条件到达后的操作。在计数条件到达之后,将会调用 barrierActionrun() 方法执行一些特殊操作
    • CountDownLatch 不能设置计数条件到达后的执行操作

常用并发工具类(锁和线程间通信工具类)相关推荐

  1. [Python]线程实例化;互斥锁;线程间通信

    目录 1.使用threading创建线程 2.线程锁(互斥锁) 线程间通信 ----------到此,结束------------ 图穷匕见 1.使用threading创建线程 threading模块 ...

  2. 线程间通信的几种方法_并发编程中的线程间通信

    线程通信的目标是使线程间能够互相发送信号.另一方面,线程通信使线程能够等待其他线程的信号. 线程通信常用的方式有: wait/notify 等待 Volatile 内存共享 CountDownLatc ...

  3. 线程间通信的几种实现方式

    线程间通信的几种实现方式 首先,要短信线程间通信的模型有两种:共享内存和消息传递,以下方式都是基本这两种模型来实现的.我们来基本一道面试常见的题目来分析: 题目:有两个线程A.B,A线程向一个集合里面 ...

  4. 【Java 并发编程】多线程、线程同步、死锁、线程间通信(生产者消费者模型)、可重入锁、线程池

    并发编程(Concurrent Programming) 进程(Process).线程(Thread).线程的串行 多线程 多线程的原理 多线程的优缺点 Java并发编程 默认线程 开启新线程 `Ru ...

  5. java 线程同步condtion_Java:多线程,使用同步锁(Lock)时利用Condition类实现线程间通信...

    [我们不仅可以使用synchronized来实现多线程同步,还可以通过创建锁对象来实现多线程的同步,还是上次模拟取现的操作,这次利用lock对象实现同步,下面是代码:    import 如果程序不使 ...

  6. Day127.JUC:线程间通信(Conditon)、并发容器类(CopyOnWrite)、JUC强大辅助类、Callable

    . 目录 一.线程间通信 线程间通信改造成Lock版  Condition 定制化调用通信 Condition 二.并发容器类 (解决集合安全问题) CopyOnWrite 写时拷贝技术 三.JUC ...

  7. Java并发——线程间通信与同步技术

    传统的线程间通信与同步技术为Object上的wait().notify().notifyAll()等方法,Java在显示锁上增加了Condition对象,该对象也可以实现线程间通信与同步.本文会介绍有 ...

  8. 【JUC并发编程03】线程间通信

    文章目录 3 线程间通信 3.1 synchronized 实现案例 3.2 虚假唤醒问题 3.3 Lock 实现案例 3 线程间通信 线程间通信有两种实现方法: 关键字 synchronized 与 ...

  9. java 编写线程公共类_Java实现线程间通信方式

    线程间通信的模型: 共享内存 消息传递 我们来做道题理解一下 题目: 有两个线程A.B,A线程向一个集合里面依次添加元素"abc"字符串,一共添加十次,当添加到第五次的时候,希望B ...

最新文章

  1. 公差基本偏差代号_《公差配合与技术测量》试题答案卷
  2. java 父类转子类_Java多态,对象转型,和简单工厂模式。希望对您有帮助!
  3. 【Android】Android中屏蔽返回键,home键以及其他实体按键
  4. (11)python里面while到底有多少知识点
  5. MSSQL → 02:数据库结构
  6. android action bar 风格,自定义ActionBar风格和样式
  7. C ++ STL中的set :: lower_bound()函数
  8. passive模式 tcp_FTP主动模式和被动模式的比较
  9. zabbix 客户端自定义端口监控
  10. 织梦当前位置对应php文件,织梦cms怎么获取当前栏目路径
  11. Anroid性能优化系列——Improving Layout Performance(二)
  12. Python 生命游戏(tkinter版)
  13. 网络蠕虫一般利用计算机系统,网络蠕虫是什么
  14. 常用数组方法汇总(ES3、ES5、ES6、ES7、ES10)
  15. MATLAB实现对比度计算
  16. Kaggle比赛—预测 DNA、RNA 和蛋白质测量如何在单细胞中共同变化
  17. 手机、手环NFC刷门禁卡
  18. Python中 *args,**args的详细用法
  19. 一文看懂 Theorem Theory Proposition Lemma Corollary Claim 的区别
  20. 查找算法【平衡二叉树】 - 平衡二叉树的创建

热门文章

  1. python—面向对象
  2. Java实现动态加载页面_[Java教程]动态加载页面数据的小工具 javascript + jQuery (持续更新)...
  3. 获取天气html,使用htmlparser获取sohu的天气预报
  4. php拼接xml特殊字符不显示,使用PHP的XML特殊字符
  5. java cpu 内存使用情况_java高cpu占用和高内存占用问题排查 (转)
  6. Java ClassLoader getResources()方法与示例
  7. c语言两个浮点数相加_C语言中两个浮点数或双精度数的模数
  8. Java类类getComponentType()方法与示例
  9. 硬核|定时任务的10种实现方案,满足你的不同需求!
  10. Jsp中使用数据库连接池