日常记录——多线程与高并发—控制器CountDownLatch、CyclicBarrier、Phaser、Semaphore、Exchanger、LockSupport

一.概念

1.CountDownLatch:计数器控制器,对初始化数量的递减直到0,允许继续运行。
2.CyclicBarrier:批量控制器,当数量到达设定值,统一执行。
3.Phaser:阶段控制器,分阶段执行逻辑,1阶段满足,2阶段才会开始。
4.Semaphore:信号控制器,信号数量控制,获取到信号的才可以执行。
5.Exchanger:只适用2个线程交换数据,基本用不到。
6.LockSupport:底层工具类,同步工具的阻塞原语。

二.使用

1.CountDownLatch:

public static void main(String[] args) {
        //初始化数量5
        System.out.println("主线程开始");
        CountDownLatch countDownLatch = new CountDownLatch(5);
        for (int i=0;i<5 ;i++){
            new Thread(() -> {
                //每个线程-1
                countDownLatch.countDown();
                System.out.println("当前计数:"+countDownLatch.getCount());
            }).start();
        }
        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //当计数为0 时 才会继续执行
        System.out.println("主线程结束");
    }

2.CyclicBarrier:

public static void main(String[] args) {
        //初始化5个线程一批   满足5个打印已满装载,出发
        CyclicBarrier cyclicBarrier = new CyclicBarrier(5,() -> {System.out.println("已满装载,出发");});
        for (int i=0;i<12;i++){
            new Thread(() ->{
                try {
                    //等待满足5个,否则阻塞
                    cyclicBarrier.await();
                    //带等待时间的阻塞,超时抛出TimeoutException 和 BrokenBarrierException
                    //cyclicBarrier.await(5, TimeUnit.SECONDS);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }

3.Phaser:

public class PhaserTest {
    //模拟5个人买彩票,1个人幸运儿中奖的情形
    static PhaserDemo phaser = new PhaserDemo();

    public static void main(String[] args) {
        //注册监听5个线程
        phaser.bulkRegister(5);
        new ThreadDemo("小李").start();
        new ThreadDemo("小张").start();
        new ThreadDemo("小王").start();
        new ThreadDemo("小华").start();
        new ThreadDemo("幸运儿").start();
    }
    static class PhaserDemo extends Phaser{

        @Override
        //int phase表示流程编号(从0开始),int registeredParties表示这个流程需要多少人参与
        protected boolean onAdvance(int phase, int registeredParties) {
        	 //return false;进行下一阶段  return true;结束
            switch (phase){
                case 0 :
                    System.out.println("所有人都买了彩票" +registeredParties);
                    return false;
                case 1 :
                    System.out.println("所有人等待开奖" +registeredParties);
                    return false;
                case 2 :
                    System.out.println("幸运儿中奖" +registeredParties);
                    return true;
                default:
                    return true;
            }
        }
    }
    //thread类
    static class  ThreadDemo extends Thread{
        private String name;
        ThreadDemo(String name){
            this.name = name;
        }
        void buy(){
            System.out.println(this.name+"买了彩票");
            //到达阶段等待执行
            phaser.arriveAndAwaitAdvance();
        }
        void waitting(){
            System.out.println(this.name+"等待开奖");
            //到达阶段等待执行
            phaser.arriveAndAwaitAdvance();
        }
        void open(){
            if(this.name.equals("幸运儿")){
                System.out.println(this.name+"中奖");
                //到达阶段等待执行
                phaser.arriveAndAwaitAdvance();
            }else{
                //到达阶段取消执行
                phaser.arriveAndDeregister();
            }

        }

        @Override
        public void run() {
            //所有人买
            buy();
            //所有人等待
            waitting();
            //幸运儿留下
            open();
        }
    }

}

4.Semaphore:

public static void main(String[] args) {
        //注册两个信号,获取到信号的才可以执行
        Semaphore semaphore = new Semaphore(2);
        for (int i=0; i<5;i++){
            new Thread(() ->{
                try {
                    //尝试获取信号 返回是否获取到
                    //semaphore.tryAcquire()
                    //获取信号 获取不到阻塞
                    semaphore.acquire();
                    System.out.println(Thread.currentThread().getName()+"获取信号");
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //释放信号
                semaphore.release();
                System.out.println(Thread.currentThread().getName()+"释放信号");
            },"线程"+i).start();
        }
    }

5.Exchanger:

public static void main(String[] args) {
        Exchanger<String> exchanger = new Exchanger<>();
        new Thread(() -> {
            String temp = "线程A变量";
            try {
                temp = exchanger.exchange(temp);
                System.out.println(Thread.currentThread().getName()+temp);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"线程A").start();
        new Thread(() -> {
            String temp = "线程B变量";
            try {
                temp = exchanger.exchange(temp);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+temp);
        },"线程B").start();
    }

6.LockSupport:

public static void main(String[] args) {
        Thread thread = new Thread(() -> {
            System.out.println("线程开始");
            for (int i = 0; i < 10 ; i++) {
                if(i == 5){
                    System.out.println("线程阻塞");
                    //使当前线程阻塞
                    LockSupport.park();
                }
                System.out.println("线程执行"+i);
            }
        });
        thread.start();
        long start = System.currentTimeMillis();
        long end = System.currentTimeMillis();
        //等待时间超过5s,打断t2线程。
        while (end-start<5000){
            end = System.currentTimeMillis();
        }
        //五秒后 唤醒入参线程
        LockSupport.unpark(thread);
    }

三、比较和场景

1.CountDownLatch:减为0后不可复用。
场景:确保一个计算不会执行,直到所需要的资源被初始化。
2.CyclicBarrier:可重复使用,当数量到达设定值,统一执行。
场景:约朋友们到某个餐厅一起吃饭,有些朋友可能会早到,有些朋友可能会晚到,但是当所有朋友到齐才会开餐。
3.Phaser:阶段性控制,可在过程中添加监视数量。
场景:分阶段执行的业务,某些阶段不允许某些条件进入。
4.Semaphore:可以定义为公平控制器,默认非公平,具有尝试获取信号功能,可自定义获取信号数量和释放数量,需要手动释放信号。
场景:银行窗口并发服务只有几个。
5.Exchanger:仅限俩个线程交换数据,了解即可。
6.LockSupport:同步工具的底层原语,如AQS。

猜你喜欢

转载自blog.csdn.net/weixin_43001336/article/details/107094331