说说CountDownLatch/CyclicBarrier/Semaphore的使用

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
上一篇:GIL锁(线程)


下一篇:线程锁(互斥锁)与GIL锁的区别