CountDownLatch/CyclicBarrier/Semaphore 使用过吗

CountDownLatch

让一些线程堵塞直到另一个线程完成一系列操作后才被唤醒。CountDownLatch 主要有两个方法,当一个或多个线程调用 await 方法时,调用线程会被堵塞,其他线程调用 countDown 方法会将计数减一(调用 countDown 方法的线程不会堵塞),当计数其值变为零时,因调用 await 方法被堵塞的线程会被唤醒,继续执行。

假设我们有这么一个场景,教室里有班长和其他6个人在教室上自习,怎么保证班长等其他6个人都走出教室在把教室门给关掉。

 

public class CountDownLanchDemo {
    public static void main(String[] args) {
        for (int i = 0; i < 6; i++) {
            new Thread(() -> {
                System.out.println(Thread.currentThread().getName() + " 离开了教室...");
            }, String.valueOf(i)).start();
        }
        System.out.println("班长把门给关了,离开了教室...");
    }
}

0 离开了教室...
1 离开了教室...
2 离开了教室...
3 离开了教室...
班长把门给关了,离开了教室...
5 离开了教室...
4 离开了教室...
发现班长都没有等其他人理他教室就把门给关了,此时我们就可以使用 CountDownLatch 来控制

public class CountDownLanchDemo {
    public static void main(String[] args) throws InterruptedException {
        CountDownLatch countDownLatch = new CountDownLatch(6);
        for (int i = 0; i < 6; i++) {
            new Thread(() -> {
                countDownLatch.countDown();
                System.out.println(Thread.currentThread().getName() + " 离开了教室...");
            }, String.valueOf(i)).start();
        }
        countDownLatch.await();
        System.out.println("班长把门给关了,离开了教室...");
    }
}
0 离开了教室...
1 离开了教室...
2 离开了教室...
3 离开了教室...
4 离开了教室...
5 离开了教室...
班长把门给关了,离开了教室...
 

 

使用枚举完成countDownLatch案例

@Setter
@Getter
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()+"国被灭.......");
                countDownLatch.countDown();
            },CountryEnum.getcountryEnum(i).getName()+"").start();
        }

        countDownLatch.await();

        System.out.println(CountryEnum.seven+"国一统华夏");
    }
}



@Getter
enum CountryEnum {
    one(1, "齐", "100", "demaxiya1"),
    two(2, "楚", "100", "demaxiya1"),
    three(3, "燕", "100", "demaxiya1"),
    four(4, "韩", "100", "demaxiya1"),
    five(5, "赵", "100", "demaxiya1"),
    six(6, "巍", "100", "demaxiya1"),
    seven(7, "秦", "100", "demaxiya1");
    private Integer id;

    private String name;
    private String time;
    private String beizhu;

    CountryEnum(Integer id, String name, String time, String beizhu) {
        this.id = id;
        this.name = name;
        this.time = time;
        this.beizhu = beizhu;
    }
    public static CountryEnum getcountryEnum(Integer id ){
        for (CountryEnum value : values()) {
           if (value.id==id){
               return value;
           }
        }
        return null;
    }
}

打印

齐国被灭.......
燕国被灭.......
楚国被灭.......
韩国被灭.......
巍国被灭.......
赵国被灭.......
seven国一统华夏

 

、CyclicBarrier(集齐七颗龙珠召唤神龙)

  1. CycliBarrier

    可循环(Cyclic)使用的屏障。让一组线程到达一个屏障(也可叫同步点)时被阻塞,知道最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续干活,线程进入屏障通过CycliBarrier的await()方法

  2. 代码示例:

    import java.util.concurrent.BrokenBarrierException;
    import java.util.concurrent.CyclicBarrier;
    
    public class CyclicBarrierDemo {
        public static void main(String[] args) {
            cyclicBarrierTest();
        }
    
        public static void cyclicBarrierTest() {
            CyclicBarrier cyclicBarrier = new CyclicBarrier(7, () -> {
                System.out.println("====召唤神龙=====");
            });
            for (int i = 1; i <= 7; i++) {
                final int tempInt = i;
                new Thread(() -> {
                    System.out.println(Thread.currentThread().getName() + "\t收集到第" + tempInt + "颗龙珠");
                    try {
                        cyclicBarrier.await();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } catch (BrokenBarrierException e) {
                        e.printStackTrace();
                    }
                }, "" + i).start();
            }
        }
    }

    打印

    2 收集到第2颗龙珠
    3 收集到第3颗龙珠
    1 收集到第1颗龙珠
    5 收集到第5颗龙珠
    4 收集到第4颗龙珠
    6 收集到第6颗龙珠
    7 收集到第7颗龙珠
    ====召唤神龙=====

     

    3、Semaphore信号量

    可以代替Synchronize和Lock

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

    2. 代码示例:

      抢车位示例:

  3. package juc.lock.SemaphoreDemo;
    
    import java.util.concurrent.Semaphore;
    
    /**
     * @Classname SemaphoreDemo
     * @Description TODO
     * @Date 2020/7/13 23:03
     * @Created by imp
     */
    public class SemaphoreDemo {
    
        public static void main(String[] args) {
            Semaphore semaphore=new Semaphore(3); //3个车位
    
            for (int i = 0; i < 6; i++) {
                new Thread(()->{
                    try {
                        //抢占车位
                        semaphore.acquire();
                        System.out.println(Thread.currentThread().getName()+"\t抢占到车位");
                        Thread.sleep(2000);
                        System.out.println(Thread.currentThread().getName()+"\t停两秒钟离开");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }finally {
                        semaphore.release();
                    }
                },String.valueOf(i)).start();
            }
        }
    }

    打印:

    0 抢占到车位
    1 抢占到车位
    4 抢占到车位
    0 停两秒钟离开
    5 抢占到车位
    1 停两秒钟离开
    4 停两秒钟离开
    2 抢占到车位
    3 抢占到车位
    5 停两秒钟离开
    3 停两秒钟离开
    2 停两秒钟离开

     

     

posted @ 2020-07-13 23:08  夜半钟声到客船  阅读(172)  评论(0编辑  收藏  举报