JUC下countDownLatch、CyclicBarrier、Semaphore以及枚举的常见使用方法

枚举类

@Getter
public enum CountryEnum {
    ONE(1, "燕"),
    TWO(2,"赵"),
    THREE(3,"韩"),
    FOUR(4,"魏"),
    FIVE(5,"齐"),
    SIX(6,"楚");

    private Integer code;
    private String mess;

    CountryEnum(Integer code, String mess) {
        this.code = code;
        this.mess = mess;
    }

    public static CountryEnum forEachCountryEnum(int index){
        CountryEnum[] values = CountryEnum.values();
        for (CountryEnum e : values) {
            if (index == e.getCode()){
                return e;
            }
        }
        return null;
    }
}

1、countDownLatch

countDownLatch是在java1.5被引入,跟它一起被引入的工具类还有CyclicBarrier、Semaphore、concurrentHashMap、BlockingQueue。

存在于java.util.cucurrent包下。

 

countDownLatch这个类使一个线程等待其他线程各自执行完毕后再执行。

是通过一个计数器来实现的,计数器的初始值是线程的数量。

每当一个线程执行完毕后,计数器的值就-1,当计数器的值为0时,表示所有线程都执行完毕,

然后在闭锁上等待的线程就可以恢复工作了。

 

即:当一个或多个线程调用await()方法时,调用线程会被阻塞,其它线调用countDown()会将计数器减1(调用countDown()方法的线程不会被阻塞),

  当计算器的值变为0时,因调用await()方法被阻塞的线程会被唤醒,继续执行;

 

代码示例:(未使用countDownLatch类)

public class CountDownLatchDemo {
    public static void main(String[] args) throws Exception {
        for (int i = 1; i <= 6; i++) {
            new Thread(() ->{
                System.out.println(Thread.currentThread().getName()+"\t国:被灭;");
            },CountryEnum.forEachCountryEnum(i).getMess()).start();
        }
        System.out.println(Thread.currentThread().getName()+"\t***大秦帝国一统华夏***");
    }
}

代码示例:(使用countDownLatch类)

public class CountDownLatchDemo {
    public static void main(String[] args) throws Exception {
        CountDownLatch countDownLatch = new CountDownLatch(6);//初始值 6个线程
        for (int i = 1; i <= 6; i++) {
            new Thread(() ->{
                System.out.println(Thread.currentThread().getName()+"\t国:被灭;");
                countDownLatch.countDown();//线程数 -1
            },CountryEnum.forEachCountryEnum(i).getMess()).start();
        }
        countDownLatch.await();//main线程等待,当countDownLatch值为0时放开;
        System.out.println(Thread.currentThread().getName()+"\t***大秦帝国一统华夏***");
    }
}

 

2、CyclicBarrier

CyclicBarrier的字面意思是可循环(Cyclic)使用的屏障(Barrier)。他要做的事情是让一组线程到达一个屏障(也可以叫同步点)时被阻塞;

直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截下来的线程才会继续执行,线程进入屏障通过CyclicBarrier的await()方法;

 

public class CyclicBarrierDemo {
    //CyclicBarrier(int parties)
    //创建一个新的 CyclicBarrier ,当给定数量的线程(线程)等待它时,它将跳闸,并且当屏障跳闸时不执行预定义的动作。
    //CyclicBarrier(int parties, Runnable barrierAction)
    //创建一个新的 CyclicBarrier ,当给定数量的线程(线程)等待时,它将跳闸,当屏障跳闸时执行给定的屏障动作,由最后一个进入屏障的线程执行。
    public static void main(String[] args) {
        CyclicBarrier cyclicBarrier = new CyclicBarrier(7, () -> {
            System.out.println("***召唤神龙***");
        });
        for (int i = 1; i <= 7; i++) {
            final int finalI = i;
            new Thread(() -> {
                System.out.println(Thread.currentThread().getName() + "\t 收集到第:" + finalI + "颗龙珠");
                try {
                    cyclicBarrier.await();//阻塞等待
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                }
            }, String.valueOf(i)).start();
        }
    }
}

 

3、Semaphore

信号量主要用于两个目的,一个用于多个共享资源的互斥作用,另一个用于并发线程数的控制;

 

Semaphore也是一个线程同步的辅助类,可以维护当前访问自身的线程个数,并提供了同步机制。

使用Semaphore可以控制同时访问资源的线程个数,例如,实现一个文件允许的并发访问数。

/**
 * public Semaphore(int permits)创建一个 Semaphore与给定数量的许可证和非公平公平设置。
 * 参数
 * permits - permits的初始许可证。 该值可能为负数,在这种情况下,必须在任何获取被授予之前发布释放。
 * <p>
 * public Semaphore(int permits,boolean fair)创建一个 Semaphore与给定数量的许可证和给定的公平设置。
 * 参数
 * permits - permits的初始许可证。 该值可能为负数,在这种情况下,必须在任何获取被授予之前发布释放。
 * fair - true如果这个信号量将保证首先在竞争中首先授予许可证,否则 false
 */
public class SemaphoreDemo {
    public static void main(String[] args) {
        Semaphore semaphore = new Semaphore(3);//模拟三个停车位
        for (int i = 1; i <= 6; i++) {//模拟6部车
            new Thread(() -> {
                try {
                    semaphore.acquire();//从该信号量获取许可证,阻止直到可用,或线程为 interrupted(被中断) 。
                    System.out.println(Thread.currentThread().getName() + "\t抢到车位");
                    TimeUnit.SECONDS.sleep(3);
                    System.out.println(Thread.currentThread().getName() + "\t停车3秒后离开车位");
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    semaphore.release();//释放许可证,将其返回到信号量。
                }
            }, String.valueOf(i)).start();
        }

    }
}

 

posted @ 2021-03-05 10:56  DHaiLin  阅读(75)  评论(0编辑  收藏  举报