7.减法计数器-加法计数器-信号量

1CountDownLatch(减法计数器)

1.CountDownLatch:减法记数器
    有三个重要方法:
        1.初始化,并确定计数器最大值
            CountDownLatch countDownLatch = new CountDownLatch(6);
        2.计数器数量-1
            countDownLatch.countDown();
        3.等待计数器归0,然后再往下执行
            countDownLatch.await();  
    样例代码如下:
        public class CountDownLatch_Test {
            public static void main(String[] args) throws InterruptedException {
                //重点1:创建CountDownLatch减法计数器,初始值为6
                CountDownLatch countDownLatch = new CountDownLatch(6);
                for (int i = 0; i < 6; i++) {
                    //重点2:每个线程间隔2秒启动
                    try {
                        TimeUnit.SECONDS.sleep(2);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    new Thread(() -> {
                        countDownLatch.countDown();
                        System.out.println(Thread.currentThread().getName() + "当前时间:" + DateTime.now() + ":数量减一 当前数量:" + countDownLatch.getCount());
                    }, "线程" + i).start();
                }
                //重点3:等待记数器归0,然后往下执行
                countDownLatch.await();
                System.out.println("所有线程等待");
            }
        }
输出:
    线程0当前时间:2021-08-04 22:52:54:数量减一 当前数量:6
    线程1当前时间:2021-08-04 22:52:56:数量减一 当前数量:5
    线程2当前时间:2021-08-04 22:52:58:数量减一 当前数量:4
    线程3当前时间:2021-08-04 22:53:00:数量减一 当前数量:3
    线程4当前时间:2021-08-04 22:53:02:数量减一 当前数量:2
    线程5当前时间:2021-08-04 22:53:04:数量减一 当前数量:1
    所有线程等待
注意点:这里不是等待所有线程都执行完毕后再执行countDownLatch.await();后的方法
而是等计数器归0,即执行了countDownLatch.countDown();后,将记数器归0,切记!
所以需要等线程都执行完毕后再执行,可以将countDownLatch.countDown()方法放在每个线程的最后!

场景:需要多个线程执行完毕/或者启动某些线程后,才能执行后续代码!

2.CyclicBarrier(加法计数器)

加法记数器:
    主要方法:
        1.构造方法,第一个参数是从0加到多少时,会执行第二个参数中的方法
            CyclicBarrier cyclicBarrier=new CyclicBarrier(7,()->{})
        2.该方法,底层会调用--count,但是也会堵塞该线程,cyclicBarrier.await()后面的代码会等CyclicBarrier条件满足后再一起执行,看下执行结果!
            cyclicBarrier.await();
样例代码如下:
    public class CyclicBarrier_Test {
        public static void main(String[] args) throws InterruptedException {
            //重点1:构造方法,如果加法计数器上达到最大值7时,会执行下面的输出方法
            CyclicBarrier cyclicBarrier=new CyclicBarrier(7,()->{
                System.out.println("召唤神龙成功!");
            });
            for (int i = 0; i < 7; i++){
                TimeUnit.SECONDS.sleep(3);
                new Thread(()->{
                    try {
                        System.out.println(Thread.currentThread().getName()+":时间:"+ DateTime.now()+" 当前数量:"+cyclicBarrier.getNumberWaiting());
                        //重点2:该方法底层会调用--count,但是会阻塞住该队列,等条件满足后,会一起执行后续方法!
                        cyclicBarrier.await();
                        System.out.println(Thread.currentThread().getName()+"等待完毕!");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } catch (BrokenBarrierException e) {
                        e.printStackTrace();
                    }
                },"线程:"+i).start();
            }
        }
    }
输出:
    线程:0:时间:2021-08-04 23:15:45 当前数量:0
    线程:1:时间:2021-08-04 23:15:48 当前数量:1
    线程:2:时间:2021-08-04 23:15:51 当前数量:2
    线程:3:时间:2021-08-04 23:15:54 当前数量:3
    线程:4:时间:2021-08-04 23:15:57 当前数量:4
    线程:5:时间:2021-08-04 23:16:00 当前数量:5
    线程:6:时间:2021-08-04 23:16:03 当前数量:6
    召唤神龙成功!
    线程:6等待完毕!
    线程:0等待完毕!
    线程:1等待完毕!
    线程:2等待完毕!
    线程:4等待完毕!
    线程:3等待完毕!
    线程:5等待完毕!

3.Semaphore(信号量)

常用方法:类似于线程池的概念
    1.获取线程资源
        semaphore.acquire();
    2.释放线程资源:
        semaphore.release();
有两个目的:
    1.用于多种共享资源的互斥使用
    2.用于并发线程的控制
样例代码如下:
    public class Semaphore_Test {
        public static void main(String[] args) {
            //类比停车场:3个停车位,有六辆车
            //重点1:规定同时访问的线程数
            Semaphore semaphore = new Semaphore(3);
            for (int i =0; i < 6; i++){
                new Thread(()->{
                    //1.获取停车位
                    try {
                        //重点2:获取线程资源
                        semaphore.acquire();
                        System.out.println(Thread.currentThread().getName()+"得到车位,停2秒!");
                        TimeUnit.SECONDS.sleep(2);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }finally {
                        System.out.println(Thread.currentThread().getName()+"开走了..");
                        //重点3:释放线程资源
                        semaphore.release();
                    }
                },"线程"+i).start();
            }
        }
    }
    输出:
        线程2得到车位,停2秒!
        线程0得到车位,停2秒!
        线程1得到车位,停2秒!
        线程0开走了..
        线程3得到车位,停2秒!
        线程1开走了..
        线程4得到车位,停2秒!
        线程2开走了..
        线程5得到车位,停2秒!
        线程5开走了..
        线程4开走了..
        线程3开走了..

结论:
    发现只能有3个线程同时访问,其他的等待!
    作用:
        1.多个共享资源互斥的使用!
        2.并发限流,控制最大额线程数!

 

posted @ 2022-05-19 21:58  努力的达子  阅读(578)  评论(0编辑  收藏  举报