1、CountDownLatch
- 让一些线程阻塞直到另外一些完成后才被唤醒
- CountDownLatch主要有两个方法,当一个或有多个线程调用await方法时,调用的线程会被阻塞.其他线程调用countDown方法计数器减1(调用countDown方法时线程不会阻塞)
- 当计数器的值变为0,因调用await方法而被阻塞的线程会被唤醒,然后继续执行该线程的操作
package com.song.CountDownLatchTest;
import java.util.concurrent.CountDownLatch;
/**
*场景案例: 秦始皇统一六国 当六国全部被灭了 才实现了统一
*/
public class CountDownLatchDemo {
public static void main(String[] args) throws InterruptedException {
CountDownLatch countDownLatch = new CountDownLatch(6);//要等待的工作线程的个数--》这里设置为六个
for (int i = 1; i <= 6; i++) {
new Thread(()->{
System.out.println(Thread.currentThread().getName()+"\t被灭");
countDownLatch.countDown();//执行一次就减一次 countDown方法计数器减1(调用countDown方法时线程不会阻塞)
},CountryEnum.getCountryEnum(i).getMessage()).start();//CountryEnum使用的枚举
}
countDownLatch.await();//当计数器的值减为0时,调用await方法被阻塞的线程(这里阻塞的线程是main)会被唤醒,继续执行
System.out.println("秦始皇一统天下");
}
}
//自定的枚举类
public enum CountryEnum {
ONE(1,"齐国"),TWO(2,"韩国"),THREE(3,"赵国"),FOUR(4,"楚国"),FIVE(5,"燕国"),SIX(6,"魏国");
private int reCode;
private String message;
CountryEnum(int reCode, String message) {
this.reCode = reCode;
this.message = message;
}
public static CountryEnum getCountryEnum(int i){
CountryEnum[] values = CountryEnum.values();
for (CountryEnum countryEnum : values) {
if (countryEnum.getReCode() == i) {
return countryEnum;
}
}
return null;
}
public int getReCode() {
return reCode;
}
public void setReCode(int reCode) {
this.reCode = reCode;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
###输出随机结果
齐国 被灭
燕国 被灭
魏国 被灭
楚国 被灭
韩国 被灭
赵国 被灭
秦始皇一统天下
Process finished with exit code 0
2、CyclicBarrier
- CyclicBarrier的字面意思是可循环(Cyclic) 使用的屏障(barrier)
- 它要做的事情是,让一组线程到达一个屏障(也可以叫做同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续干活,线程进入屏障通过CyclicBarrier的await()方法.
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
/**
*场景案例:集齐七龙珠召唤神龙
*/
public class CyclicBarrierDemo {
public static void main(String[] args) {
//其参数表示屏障拦截的线程数量 ----》这里拦截数量为7
CyclicBarrier cyclicBarrier=new CyclicBarrier(7,()->{
System.out.println("召唤神龙");
});
//当以下线程全部到达屏障(都参与线程调用了await方法)时 才会执行后续操作
for (int i = 1; i <=7; i++) {
final int temp = i;
new Thread(()->{
System.out.println(Thread.currentThread().getName()+"\t 收集到第"+ temp +"颗龙珠");
try {
//告诉CyclicBarrier我已经到达了屏障,然后当前线程被阻塞。
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
},String.valueOf(i)).start();
}
}
}
###输出的随机结果
3 收集到第3颗龙珠
5 收集到第5颗龙珠
1 收集到第1颗龙珠
2 收集到第2颗龙珠
6 收集到第6颗龙珠
4 收集到第4颗龙珠
7 收集到第7颗龙珠
召唤神龙
Process finished with exit code 0
3、Semaphore
- 是一个线程同步的辅助类,可以维护当前访问自身的线程个数,并提供了同步机制。使用Semaphore(信号量)的主要两个目的,一个是用于多个共享资源的相互排斥使用,另一个用于并发资源数的控制.
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
/**
*
*场景模拟:停车场停车 总共有3个车位 6俩车去停 每个车停三秒开走
*/
public class SemaphoreDemo {
public static void main(String[] args) {
Semaphore semaphore = new Semaphore(3);//模拟3个停车位
for (int i = 1; i <= 6; i++) {
new Thread(()->{
try {
//抢到资源
semaphore.acquire();
System.out.println(Thread.currentThread().getName()+"\t 号车抢到了停车位");
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"\t 号车停了三秒走了");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
//释放资源
semaphore.release();
}
},String.valueOf(i)).start();
}
}
}
###输出的随机结果
1 号车抢到了停车位
3 号车抢到了停车位
2 号车抢到了停车位
2 号车停了三秒走了
3 号车停了三秒走了
4 号车抢到了停车位
1 号车停了三秒走了
5 号车抢到了停车位
6 号车抢到了停车位
6 号车停了三秒走了
4 号车停了三秒走了
5 号车停了三秒走了
Process finished with exit code 0