线程间配合:Condition、Semaphore、CountDownLatch、CyclicBarrier
1 重入锁的好搭档:Condition条件
如果大家理解了Object.wait()和Object.notify()方法的话,那么就能很容易理解Condition接口了。它和wait()和notify()方法的作用大致是相同的。我们通过重入锁Lock接口的new Condition()方法可以生成一个与当前重入锁绑定的Condition实例。利用Condition对象,我们就可以让线程在合适的时间等待,或者在某一特定时刻得到通知,继续执行。顺带一提,Condition接口的实现类是ConditionObject。
Condition接口的基本方法如下:
public interface Condition {
void await() throws InterruptedException;
void awaitUninterruptibly();
long awaitNanos(long nanosTimeout) throws InterruptedException;
boolean await(long time, TimeUnit unit) throws InterruptedException;
boolean awaitUntil(Date deadline) throws InterruptedException;
void signal();
void signalAll();
}
以上方法的含义如下:
await():该方法会使当前线程在Condition队列(等待池)中等待,同时释放当前锁。当其他线程中使用signal()或者signalAll()方法时,线程会被唤醒并且加入到锁池中,准备竞争锁;或者当线程被中断时,也能跳出等待。awaitUninterruptibly(),该方法与await()基本相同,只不过不会在等待过程中响应中断。signal()方法用于唤醒一个处于等待池的线程,而signalAll()会唤醒所有处于等待池的线程。
2 允许多个线程同时访问:信号量(Semaphore)
信号量为多线程写作提供了更为强大的控制方法。无论是内部锁synchronized还是重入锁ReentrantLock,一次都只允许一个线程访问一个资源,而信号量却可以指定多个线程同时访问某一个资源。信号量主要提供了以下构造函数:
public Semaphore(int permits);
public Semaphore(int permits, boolean fair);
在构造信号量对象时,必须要指定信号量的准入数,即同时能申请多少个许可。当每个线程每次只申请一个许可时,这就相当于指定了同时有多少个线程可以访问某一个资源。信号量的主要逻辑方法有:
public void acquire();
public void acquireUninterruptibly();
public boolean tryAquire();
public boolean tryAquire(long timeout, TimeUnit unit);
public void release();
acquire()方法尝试获得一个准入的许可,若无法获得,则线程会等待,直到有线程释放许可或者当前线程被中断。acquireUninterruptibly()方法和acquire()方法类似,但是不相应中断。tryAcquire()尝试获得一个许可,如果成功则返回true,失败则返回false,它不会进行等待,立即返回。release()用于在线程访问资源结束后,释放一个许可,以使其他等待许可的线程可以进行资源访问。
3 倒计时器:CountDownLatch
CountDown在英文中意为倒计数,Latch为门闩的意思。在这里,门闩的含义是:把门锁起来,不让里面的线程跑出来,因此这个工具通常用来控制线程等待,它可以让某一个线程等待直到倒计时结束,再开始执行。
CountDownLatch的构造函数接收一个整数作为参数,即当前这个计数器的计数个数。请看下面的示例:
/**
* @author mutianjie
* @date 2020/5/15 10:22 上午
* 对于火箭发射,为了保证万无一失,往往要进行各种检查,等所有设备检查完毕后才能点燃引擎。
*/
public class CountDownLatchDemo implements Runnable{
static final CountDownLatch end = new CountDownLatch(20);
static final CountDownLatchDemo demo = new CountDownLatchDemo();
@Override
public void run() {
try {
// 模拟检查任务
Thread.sleep(new Random().nextInt(10) * 1000);
System.out.println("Check Complete!");
end.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws InterruptedException {
ExecutorService exec = Executors.newFixedThreadPool(10);
for (int i = 0; i < 10; i++) {
exec.submit(demo);
}
// 等待检查
// 官方Javadoc:Causes the current thread to wait until the latch has counted down to zero,
// unless the thread is interrupted.
end.await();
// 发射火箭
System.out.println("Fire!");
exec.shutdown();
}
}
主线程执行end.await()等待,直到计数器减为0之后才继续执行。
4 循环栅栏:CyclicBarrier
CyclicBarrier是另外一种多线程并发控制工具。CyclicBarrier可以理解为循环栅栏。栅栏就是一种障碍物,比如,通常在私人宅邸的周围就可以围上一圈栅栏,阻止闲杂人等入内。这里当然是用来阻止线程继续执行,要求线程在栅栏处等待。而这里循环的意思,也就是说这个计数器可以循环使用。比如,我们假设将计数器设置为10,那么凑齐第一批10个线程后,计数器就会归零,然后接着凑齐下一批10个线程。
CyclicBarrier的构造函数除了接收计数总数parties,还可以接收一个参数Runnable barrierAction,这个参数表示当计数器完成一轮计数之后,系统会执行的动作。
public CyclicBarrier(int parties, Runnable barrierAction)
举个例子:
public class CyclicBarrierDemo {
static class TaskThread extends Thread {
CyclicBarrier barrier;
public TaskThread(CyclicBarrier barrier) {
this.barrier = barrier;
}
@Override
public void run() {
try {
Thread.sleep(1000);
System.out.println(getName() + " 到达栅栏 A");
barrier.await();
System.out.println(getName() + " 冲破栅栏 A");
Thread.sleep(2000);
System.out.println(getName() + " 到达栅栏 B");
barrier.await();
System.out.println(getName() + " 冲破栅栏 B");
} catch (Exception e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
int threadNum = 5;
CyclicBarrier barrier = new CyclicBarrier(threadNum, new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " 完成最后任务");
}
});
for(int i = 0; i < threadNum; i++) {
new TaskThread(barrier).start();
}
}
}
打印结果:
Thread-1 到达栅栏 A
Thread-3 到达栅栏 A
Thread-0 到达栅栏 A
Thread-4 到达栅栏 A
Thread-2 到达栅栏 A
Thread-2 完成最后任务
Thread-2 冲破栅栏 A
Thread-1 冲破栅栏 A
Thread-3 冲破栅栏 A
Thread-4 冲破栅栏 A
Thread-0 冲破栅栏 A
Thread-4 到达栅栏 B
Thread-0 到达栅栏 B
Thread-3 到达栅栏 B
Thread-2 到达栅栏 B
Thread-1 到达栅栏 B
Thread-1 完成最后任务
Thread-1 冲破栅栏 B
Thread-0 冲破栅栏 B
Thread-4 冲破栅栏 B
Thread-2 冲破栅栏 B
Thread-3 冲破栅栏 B
线程间配合:Condition、Semaphore、CountDownLatch、CyclicBarrier的更多相关文章
- 线程间同步之 semaphore(信号量)
原文地址:http://www.cnblogs.com/yuqilin/archive/2011/10/16/2214429.html semaphore 可用于进程间同步也可用于同一个进程间的线程同 ...
- JDK5.0 特性-线程同步装置之Semaphore
来自:http://www.cnblogs.com/taven/archive/2011/12/17/2291474.html import java.util.ArrayList; import j ...
- Java多线程编程(5)--线程间通信
一.等待与通知 某些情况下,程序要执行的操作需要满足一定的条件(下文统一将其称之为保护条件)才能执行.在单线程编程中,我们可以使用轮询的方式来实现,即频繁地判断是否满足保护条件,若不满足则继续判断 ...
- Java 如何实现线程间通信?(notify、join、CountdownLatch、CyclicBarrier、FutureTask、Callable )
转自:https://mp.weixin.qq.com/s?__biz=MzI4Njc5NjM1NQ==&mid=2247486499&idx=1&sn=d3f2d6959df ...
- 等待某(N)个线程执行完再执行某个线程的几种方法(Thread.join(),CountDownLatch,CyclicBarrier,Semaphore)
1.main线程中先调用threadA.join() ,再调用threadB.join()实现A->B->main线程的执行顺序 调用threadA.join()时,main线程会挂起,等 ...
- 并发包下常见的同步工具类详解(CountDownLatch,CyclicBarrier,Semaphore)
目录 1. 前言 2. 闭锁CountDownLatch 2.1 CountDownLatch功能简介 2.2 使用CountDownLatch 2.3 CountDownLatch原理浅析 3.循环 ...
- Java中的4个并发工具类 CountDownLatch CyclicBarrier Semaphore Exchanger
在 java.util.concurrent 包中提供了 4 个有用的并发工具类 CountDownLatch 允许一个或多个线程等待其他线程完成操作,课题点 Thread 类的 join() 方法 ...
- AQS之CountDownLatch、Semaphore、CyclicBarrier
CountDownLatch A synchronization aid that allows one or more threads to wait until a set of operatio ...
- CountDownLatch/CyclicBarrier/Semaphore 使用过吗?
CountDownLatch/CyclicBarrier/Semaphore 使用过吗?下面详细介绍用法: 一,(等待多线程完成的)CountDownLatch 背景; countDownLatch ...
随机推荐
- 动态ip服务器 动态ip服务器的常用连接方式 收藏版
动态ip服务器目前比较常用的是VPS也叫作虚拟机.目前比较小型的vps服务器与普通电脑没什么区别,最大的区别就是用户连接zhidao服务器内的ip是固定不变的.而服务器运行的ip是可以动态的. 实现动 ...
- [05]HTML基础之表格标签
1. <table>标签 表格容器,尽量避免用属性书写样式,而是用CSS来表达 border: 数字 //表格边框宽度 2. <caption>标签 表格的标题,一般出现在表格 ...
- golang内置类型和内置函数
golang内置类型和内置函数是不需要引入包直接可用的 golang内置类型: 数值类型 string int,unint float32,float64 bool array 有长度的 comple ...
- Java实现蓝桥杯历届试题兰顿蚂蚁
历届试题 兰顿蚂蚁 时间限制:1.0s 内存限制:256.0MB 提交此题 问题描述 兰顿蚂蚁,是于1986年,由克里斯·兰顿提出来的,属于细胞自动机的一种. 平面上的正方形格子被填上黑色或白色.在其 ...
- Java实现 蓝桥杯VIP 基础练习 分解质因数
题目介绍 问题描述 求出区间[a,b]中所有整数的质因数分解. 输入格式 输入两个整数a,b. 输出格式 每行输出一个数的分解,形如k=a1a2a3-(a1<=a2<=a3-,k也是从小到 ...
- Java实现 LeetCode 417 太平洋大西洋水流问题
417. 太平洋大西洋水流问题 给定一个 m x n 的非负整数矩阵来表示一片大陆上各个单元格的高度."太平洋"处于大陆的左边界和上边界,而"大西洋"处于大陆的 ...
- Java实现 LeetCode 71 简化路径
71. 简化路径 以 Unix 风格给出一个文件的绝对路径,你需要简化它.或者换句话说,将其转换为规范路径. 在 Unix 风格的文件系统中,一个点(.)表示当前目录本身:此外,两个点 (-) 表示将 ...
- Java实现 洛谷 P1508 Likecloud-吃、吃、吃
import java.util.Arrays; import java.util.Scanner; public class Main { static int n, m; static int[] ...
- Linux 用户管理命令-userdel和su
userdel [选项] 用户名,可以删除用户,常用选项 -r :删除用户的同时删除用户的家目录,一般都要用,例如:userdel -r xbb 新建用户和删除用户的本质也就是修改了 /etc/sha ...
- PAT 挖掘机技术哪家强
为了用事实说明挖掘机技术到底哪家强,PAT 组织了一场挖掘机技能大赛.现请你根据比赛结果统计出技术最强的那个学校. 输入格式: 输入在第 1 行给出不超过 105 的正整数 N,即参赛人数.随后 N ...