JUC并发包
CountDownLatch(多等一)
CountDownLatch:是java.util.concurrent并发包下的一个工具类,其意思“倒计时门闩”,它允许一个或多个线程一直等待直到其他线程执行完毕才开始执行
简单来讲就是:
多个人等一个信号后继续执行操作:例如5个运动员,等一个发令员的枪响。
不足:
1: CountDownLatch是不能够重用的
根据上面的解析,大家也发现,共享锁加锁的操作并不会增加state的值。CountDownLatch中state一旦变成0就没有提供其他方式增长回去了。
所以CountDownLatch是一次性消耗品,用完就得换新的。这样设计也是比较正常的,对状态的要求比较严格,例如已经开始比赛了你再告诉裁判说,这次再加5个人,比赛都进行一半了,不会考虑再回去的。随意修改约束值会带来很多逻辑上的问题。
2: 如果没有指定失效时间的话会无限等待
代码示例
package com.rj.bd.zy.JUCPackage.countDownLatchs;
import java.util.concurrent.CountDownLatch;
/**
* @desc 第一题
* @author 高增源
* @time 2021年10月26日
*/
public class Test01 {
public static void main(String[] args) throws InterruptedException {
CountDownLatch countDownLatch=new CountDownLatch(10);
for (int i = 0; i < 10; i++) {
new Thread(()->{
System.out.println("选手"+Thread.currentThread().getName()+":开始跑步");
try {
Thread.sleep((int)Math.random()*1000);//耗时模拟选手跑步
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("选手"+Thread.currentThread().getName()+":跑到终点");
countDownLatch.countDown();//让计数器减一
}).start();
}
//等待所有选手跑完
countDownLatch.await();
//输出打印比赛结束
System.out.println("比赛结束");
}
}
如果有需要多线程重用的时候该怎么办,为此就引出了我们接下来要讲的CyclicBarrier类
CyclicBarrier
翻译成中文就是”循环栅栏/障碍“,可以使一定数量的线程反复地在栅栏位置处汇集。当线程到达栅栏位置时将调用await方法.
这个方法将阻塞直到所有线程都到达栅栏位置。如果所有线程都到达栅栏位置,那么栅栏将打开,此时所有的线程都将被释放,而栅栏将被重置以便下次使用。
可重用:
它有reset方法将栅栏重置为初始值
代码示例
package com.rj.bd.zy.JUCPackage.CyclicBarriers;
/**
* @desc 学生类:模拟去吃饭,人齐再开饭
* @author 高增源
* @time 2021年10月26日
*/
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
public class student extends Thread{
CyclicBarrier cyclicBarrier;
public student(CyclicBarrier cyclicBarrier) {
this.cyclicBarrier = cyclicBarrier;
}
@Override
public void run() {
System.out.println("小伙伴"+Thread.currentThread().getName()+"出发了");
try {
Thread.sleep((int)(Math.random()*2000));//耗时操作模拟出发到到达耗时
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("小伙伴"+Thread.currentThread().getName()+"到了");
try {
cyclicBarrier.await();//到达之后等待,等所有人到后开饭
} catch (InterruptedException | BrokenBarrierException e) {
e.printStackTrace();
}
System.out.println("小伙伴"+Thread.currentThread().getName()+"说:人齐了开饭");
}
}
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
//====================================================================
/**
* @desc 第一题测试类:测试学生类
* @author 高增源
* @time 2021年10月26日
*/
public class Test01 {
public static void main(String[] args) throws InterruptedException, BrokenBarrierException {
//设置一个栅栏计数器
CyclicBarrier cyclicBarrier=new CyclicBarrier(5);
for (int i = 0; i < 5; i++) {
new student(cyclicBarrier).start();
}
}
}
Semaphore
Semaphore可以用于做流量控制,特别公用资源有限的应用场景,比如数据库连接。
假如有一个需求,要读取几万个文件的数据,因为都是IO密集型任务,我们可以启动几十个线程并发的读取,但是如果读到内存后,还需要存储到数据库中,而数据库的连接数只有10个,这时我们必须控制只有十个线程同时获取数据库连接保存数据,否则会报错无法获取数据库连接。这个时候,我们就可以使用Semaphore来做流控
类比:新生开学的时候,假如有1000人,河软只有3个门,所以我们只能同时开启3个门迎接新生。
semaphore.acquire();//请求令牌
semaphore.release();//释放令牌
代码示例
package com.rj.bd.zy.JUCPackage.Semaphores.zy1;
import java.util.concurrent.Semaphore;
/**
* @desc 老师类:今天有20个学生考试了,而老师每次最多只能看3个人的答案
* @author 高增源
* @time 2021年10月26日
*/
public class Teacher {
public static void main(String[] args) {
//设置最大线程并行数
Semaphore semaphore=new Semaphore(3);
for (int i = 0; i < 20; i++) {
new Student("同学"+i).JiaoZuoYe(semaphore);
}
}
}
package com.rj.bd.zy.JUCPackage.Semaphores.zy1;
import java.util.concurrent.Semaphore;
/**
* @desc 学生类
* @author 高增源
* @time 2021年10月26日
*/
public class Student {
private String name;
public Student(String name) {
this.name = name;
}
public void JiaoZuoYe(Semaphore semaphore){
new Thread(()->{
System.out.println(name+" 交作业等老师批");
try {
semaphore.acquire();//请求令牌
Thread.sleep((int)(Math.random()*1000));//设置随机延时操作,模拟老师批作业耗时
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(name+" 老师批完了");
semaphore.release();//释放令牌
}).start();
}
}