CountDownLatch
latch:门闩、插销、碰锁、弹簧锁;
如果没有CountDownLatch
class Scratch {
public static void main(String[] args) {
for(int i=0;i<6;i++){
new Thread(()->{
System.out.println(Thread.currentThread().getName()+"\t 完成");
},String.valueOf(i)).start();
}
System.out.println(Thread.currentThread().getName()+"\t 最终完成");
}
}
main线程会直接完成,而不等待其他线程的工作。
使用CountDownLatch
import java.util.concurrent.CountDownLatch;
class Scratch {
public static void main(String[] args) throws Exception{
CountDownLatch countDownLatch = new CountDownLatch(6);
for(int i=0;i<6;i++){
new Thread(()->{
System.out.println(Thread.currentThread().getName()+"\t 完成");
countDownLatch.countDown();
},String.valueOf(i)).start();
}
countDownLatch.await();
System.out.println(Thread.currentThread().getName()+"\t 最终完成");
}
}
使用枚举的CountDownLatch
import jdk.nashorn.internal.objects.annotations.Getter;
public enum CountryEnum{
ONE(1,"齐"),TWO(2,"楚"),THREE(3,"燕"),FOUR(4,"韩"),FIVE(5,"赵"),SIX(6,"魏");
private Integer retCode;
private String retMessage;
CountryEnum(Integer retCode, String retMessage) {
@Getter this.retCode = retCode;
@Getter this.retMessage =retMessage;
}
public static CountryEnum forEach_CountryEnum(int index){
CountryEnum[] myArray = CountryEnum.values();
for(CountryEnum element:myArray){
if(index==element.getRetCOde()){
return element;
}
}
return null;
}
}
import java.util.concurrent.CountDownLatch;
class Scratch {
public static void main(String[] args) throws Exception{
CountDownLatch countDownLatch = new CountDownLatch(6);
for(int i=0;i<6;i++){
new Thread(()->{
System.out.println(Thread.currentThread().getName()+"\t 完成");
countDownLatch.countDown();
},CountryEnum.forEach_CountryEnum(i).getRetMessage()).start();
}
countDownLatch.await();
System.out.println(Thread.currentThread().getName()+"\t 最终完成");
}
public static void close() throws InterruptedException{
CountDownLatch countDownLatch = new CountDownLatch(6);
for(int i=0;i<6;i++){
new Thread(()->{
System.out.println(Thread.currentThread().getName()+"\t 完成");
countDownLatch.countDown();
},String.valueOf(i)).start();
}
countDownLatch.await();
System.out.println(Thread.currentThread().getName()+"\t 最终完成");
}
}
小总结:CountDownLatch这个类使一个线程等待其他线程各自执行完毕后再执行。是通过一个计数器来实现的,计数器的初始值是线程的数量。每当一个线程执行完毕后,计数器的值就-1,当计数器的值为0时,表示所有线程都执行完毕,然后再闭锁上等待的线程就可以恢复工作了。
※CountDownLatch主要有两个方法,当一个或多个线程调用await方法时,调用线程会被阻塞,其它线程调用countDown方法会将计数器减1(调用CountDown的线程不会被阻塞),当计数器的值变为0,调用await方法被阻塞的线程被唤醒,继续执行。
CyclicBarrier
Cyclic 循环,Barrier屏障
(集齐七颗龙珠召唤神龙)
CyclicBarrier :可循环使用的屏障。他做的事情是:让一组线程到达一个屏障(也可以叫做同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续干活,线程进入屏障通过CyclicBarrier的await方法。
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
class Scratch {
public static void main(String[] args) throws Exception {
CyclicBarrier cyclicBarrier = new CyclicBarrier(7,()->{System.out.println("召唤神龙!");});
for (int i = 0; i < 7; i++) {
final int tmp = i;
new Thread(() -> {
System.out.println(Thread.currentThread().getName() + "\t 收集到第: "+tmp+"龙珠");
try{
cyclicBarrier.await();
}catch(InterruptedException e){
e.printStackTrace();
}catch (BrokenBarrierException e){
e.printStackTrace();
}
}, String.valueOf(i)).start();
}
}
}
Semaphore
Semaphore:信号标、信号量
信号量主要用于两个目的:一个是用于多个共享资源的互斥使用,另一个是用于并发线程数的控制。
【抢车位为例】
import java.util.concurrent.*;
class Scratch {
public static void main(String[] args) throws Exception {
Semaphore semaphore = new Semaphore(3);//只有3个车位
for (int i = 0; i < 6; i++) { //6辆车
final int tmp = 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 停车3秒后离开车位");
}catch(InterruptedException e){
e.printStackTrace();
}finally {
semaphore.release();
}
}, String.valueOf(i)).start();
}
}
}