Day299.控制并发流程 -Juc
Posted 阿昌喜欢吃黄桃
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Day299.控制并发流程 -Juc相关的知识,希望对你有一定的参考价值。
控制并发流程
一、什么是控制并发流程?
- 作用
帮助程序员更容易得让线程之间相互配合,来满足业务逻辑;让各个线程之间动作协调
- 比如
让线程A等待线程B执行完后再执行等待合作策略;
或一系列线程等待一个线程运行完毕或发号等…
二、控制并发流程工具类
三、CountDownLatch倒计时门栓
倒数count为0后,执行await()方法阻塞的线程就发车
1、类作用
过山车,人满了指挥员一声令下发车
- 流程
倒数结束之前,一直处于等待
状态,直到倒计时结束。此线程才继续
工作。
2、主要方法
3、图解
在构造方法中指定倒数count值;
调用await的线程会被挂起;
每调用countDown(),倒数count会减1;但是不会被挂起,依然执行
当倒数count值为0时,被await的线程就被释放,开始执行
4、代码演示
- 用法一:
1等多
可以多线程同时执行
一个线程等待多个线程都执行完毕,再继续自己的工作
/******
@author 阿昌
@create 2021-06-15 20:48
*******
* 工厂中,质检,5个工人检查,当5个人都认为通过,才认为这个质检通过
*/
public class CountDownLatchDemo1 {
public static void main(String[] args) throws InterruptedException {
CountDownLatch countDownLatch = new CountDownLatch(5);//指定倒数count为5
ExecutorService pool = Executors.newFixedThreadPool(5);//线程池创建5个线程
//5次任务质检
for (int i = 0; i < 5; i++) {
int no = i+1;
Runnable runnable = new Runnable() {
@Override
public void run() {
try {
Thread.sleep((long) (Math.random() * 10000));
System.out.println("No." + no + ":质检完毕");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
countDownLatch.countDown();//倒计count减1
}
}
};
pool.submit(runnable);
}
System.out.println("等待5个人质检完。。。。。");
countDownLatch.await();//主线程等待倒时count=0,释放所有挂起线程,并主线进行工作
System.out.println("质检完成");
}
}
- 用法二:
多等1
多个线程等待某个线程的信号,同时开始执行
/******
@author 阿昌
@create 2021-06-15 20:48
*******
* 模拟100m跑步,5名选手都准备好了,只能裁判员一生令下,5人同时跑出
*/
public class CountDownLatchDemo2 {
public static void main(String[] args) throws InterruptedException {
CountDownLatch countDownLatch = new CountDownLatch(1);
ExecutorService pool = Executors.newFixedThreadPool(5);//线程池创建5个线程
for (int i = 0; i < 5; i++) {
int no = i+1;
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println("NO." + no + ":准备完毕,等待发令");
try {
countDownLatch.await();
System.out.println("No." + no + ":开始跑步");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
pool.submit(runnable);
}
//主线程,模拟裁判员
Thread.sleep(5000);
System.out.println("发令枪响,比赛开始");
countDownLatch.countDown();
}
}
- 用法三:综合用法,1等多&多等1
1等多:裁判员等5名运动员到达终点
多等1:5名运动员等待裁判员打枪开跑
/******
@author 阿昌
@create 2021-06-15 20:48
*******
* 模拟100m跑步,5名选手都准备好了,只能裁判员一生令下,5人同时跑出,当所有人都到终点后,比赛结束
*/
public class CountDownLatchDemo3 {
public static void main(String[] args) throws InterruptedException {
CountDownLatch begin = new CountDownLatch(1);
CountDownLatch end = new CountDownLatch(5);
ExecutorService pool = Executors.newFixedThreadPool(5);//线程池创建5个线程
for (int i = 0; i < 5; i++) {
int no = i+1;
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println("NO." + no + ":准备完毕,等待发令");
try {
begin.await();
System.out.println("No." + no + ":开始跑步");
Thread.sleep((long) (Math.random()*10000));
System.out.println("No." + no + ":到达终点");
end.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
end.countDown();
}
}
};
pool.submit(runnable);
}
//主线程,模拟裁判员
Thread.sleep(5000);
System.out.println("发令枪响,比赛开始");
begin.countDown();
end.await();
System.out.println("比赛结束!!!");
}
}
5、注意点
- 他不能
重用
,当倒数count=0,就失效了; - 如果要再次使用,
再实例化新的对象
- 可以实现
多等多
的情况
6、总结
四、Semaphore信号量
1、类作用
用于一些重量级服务,如执行时间长、处理消耗资源大;来设置同时并发执行任务线程个数,只能有拿到许可证的线程才可以执行
-
用来
限制
或管理数量的有限资源
的使用情况 -
类比生活中的:
"许可证"
-
这个许可证的数量
有限
2、图解
3、使用流程
4、主要方法
5、代码演示
- 一般用法:
public class SemaphoreDemo {
static Semaphore semaphore = new Semaphore(3,true);
public static void main(String[] args) {
ExecutorService pool = Executors.newFixedThreadPool(50);
for (int i = 0; i < 100; i++) {
pool.submit(new Task());
}
pool.shutdown();
}
static class Task implements Runnable{
@Override
public void run() {
try {
semaphore.acquire();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+":拿到许可证");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+":释放的许可证");
semaphore.release();
}
}
}
- 特殊用法
6、注意点
-
获取&释放
的数量要求必须一致
,否则程序会卡死 -
根据情况设置
公平性
,一般设置为true -
释放和获取对线程没有要求,
可以由这个线程获取,别的线程释放
-
可以将它实现成一个
轻量级的CountDownLatch
五、Condition条件对象
1、类作用
2、图解
3、signalAll()和signal()的区别
- signalAll()唤醒
所有
等待的线程 - signal()是
公平
的,唤醒等待时间最长的线程
4、代码演示
condition一般与lock进行搭配使用
- 普通用法
public class ConditionDemo1 {
private ReentrantLock lock = new ReentrantLock();
private Condition condtion = lock.newCondition();
void method1() throws InterruptedException {
lock.lock();
try{
System.out.println("条件不满足,开始wait");
condtion.await();
System.out.println("条件满足,开始执行后续的任务");
}finally {
lock.unlock();
}
}
void method2(){
lock.lock();
try{
System.out.println("准备工作完成,开始唤醒其他线程");
condtion.signal();
}finally {
lock.unlock();
}
}
//主函数
public static void main(String[] args) throws InterruptedException {
ConditionDemo1 demo1 = new ConditionDemo1();
//主线程创建一个线程1
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000);
demo1.method2();//线程1,1秒后,唤醒主线程
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
demo1.method1();//主线程阻塞
}
}
- 用Condition实现生产者消费者模式
/******
@author 阿昌
@create 2021-06-15 22:01
*******
* 演示Condition实现生产者消费者模式
*/
public class ConditionDemo2 {
private static int queueSize = 10;
private static PriorityQueue<Integer> queue = new PriorityQueue<>(queueSize);
private static ReentrantLock lock = new ReentrantLock();
private static Condition noFull = lock.newCondition();
private static Condition notEmpty = lock.newCondition();
//消费者
static class Consumer extends Thread {
@Override
public void run() {
comsume();
}
//消费操作
void comsume(){
while (true){
lock.lock();
try {
while (queue.size()==0){
System.out.println("队列空,等待数据");
notEmpty.await();
}
queue.poll();
noFull.signalAll();
System.out.println("从队列里取走了一个数据,队列还剩余空间"+(queueSize-queue.size())+"个元素");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
//生产者
static class Producer extends Thread {
@Override
public void run() {
produce();
}
//生产操作
void produce(){
while (true){
lock.lock();
try {
while (queue.size()==queueSize){
System.out.println("队列满,等待消费");
noFull.await();
}
queue.offer(1);
notEmpty.signalAll();
System.out.println("给队列生成了一个数据,队列有"+queue.size()+"个元素");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
//主函数
public static void main(String[] args) {
Consumer consumer = new Consumer();
Producer producer = new Producer();
consumer.start();
producer.start();
}
}
5、注意点
await会自动释放锁,无需手动释放
六、CyclicBarrier循环栅栏
满足数量条件,就发车
1、类作用
2、代码演示
它是可以重用
的!!!!!!!!
public class CyclicBarrierDemo {
public static void main(String[] args) {
//参数1:设置几个等待数
//参数2:当线程数满足条件后,执行的任务
CyclicBarrier cyclicBarrier = new CyclicBarrier(5, new Runnable() {
@Override
public void run() {
System.out.println("这一波人到齐了,出发");
}
});
//创建10个线程
for (int i = 0; i < 10; i++) {
new Thread(new Task(i,cyclicBarrier)).start();
}
}
static class Task implements Runnable{
private int id;
private CyclicBarrier cyclicBarrierDay1[下] - Python基础 基本语法流程控制