7. JUC强大辅助类(减少计数CountDownLatch,循环栅栏CyclicBarrier,信号灯Semaphore)便于解决并发功能

news/2024/5/20 8:11:09 标签: java, 线程, juc, 多线程, 辅助并发类

该辅助类主要讲述三个
减少计数CountDownLatch  循环栅栏 CyclicBarrier  信号灯Semaphore

7.1 CountDownLatch

该类的构造方法为
CountDownLatch(int count)构造一个用给定计数初始化的CountDownLatch在这里插入代码片

两个常用的主要方法
await() 使当前线程在锁存器倒计数至零之前一直在等待,除非线程被中断
countDown()递减锁存器的计数,如果计数达到零,将释放所有等待的线程

CountDownLatch 类可以设置一个计数器,然后通过 countDown 方法来进行减 1 的操作,使用 await 方法等待计数器不大于 0,然后继续执行 await 方法之后的语句
具体步骤可以演化为定义一个类,减1操作,并等待到0,为0执行结果

通过具体的案例进行加深代码
6个同学陆续离开教室之后,班长才能锁门
如果不加 CountDownLatch类,会出现线程混乱执行,同学还未离开教室班长就已经锁门了

java">public class CountDownLatchDemo {
    //6个同学陆续离开教室之后,班长锁门
    public static void main(String[] args) throws InterruptedException {
        //6个同学陆续离开教室之后
        for (int i = 1; i <=6; i++) {
            new Thread(()->{
                System.out.println(Thread.currentThread().getName()+" 号同学离开了教室");
            },String.valueOf(i)).start();
        }
        System.out.println(Thread.currentThread().getName()+" 班长锁门走人了");
    }
}

 

 这就造成了,线程的混乱问题 ,可以通过CountDownLatch计数,直到为0 ,才结束

java">//演示 CountDownLatch
public class CountDownLatchDemo {
    //6个同学陆续离开教室之后,班长锁门
    public static void main(String[] args) throws InterruptedException {
        //创建CountDownLatch对象,设置初始值
        CountDownLatch countDownLatch = new CountDownLatch(6);
        //6个同学陆续离开教室之后
        for (int i = 1; i <=6; i++) {
            new Thread(()->{
                System.out.println(Thread.currentThread().getName()+" 号同学离开了教室");
                //计数  -1
                countDownLatch.countDown();
            },String.valueOf(i)).start();
        }
        //等待,直到达到 0 
        countDownLatch.await();
        System.out.println(Thread.currentThread().getName()+" 班长锁门走人了");
    }
}

 7.2 CyclicBarrier

该类是 允许一组线程 互相 等待,直到到达某个公共屏障点,在设计一组固定大小的线程的程序中,这些线程必须互相等待,因为barrier在释放等待线程后可以重用,所以称为循环barrier

常用的构造方法有:
CyclicBarrier(int parties,Runnable barrierAction)创建一个新的CyclicBarrier,它将在给定数量的参与者线程)处于等待状态时启动,并在启动barrier时执行给定的屏障操作,该操作由最后一个进入barrier的线程操作

常用的方法有:
await()在所有的参与者都已经在此barrier上调用await方法之前一直等待

通过具体案例
   集齐7颗龙珠就可以召唤神龙

 CyclicBarrier 的构造方法第一个参数是目标障碍数,每次执行 CyclicBarrier 一次障碍数会加一,如果达到了目标障碍数,才会执行 cyclicBarrier.await()之后的语句。可以将 CyclicBarrier 理解为加 1 操作

java">//集齐7颗龙珠就可以召唤神龙
public class CyclicBarrierDemo {
    //创建固定值
    private static final int NUMBER = 7;
    public static void main(String[] args) {
        //创建CyclicBarrier
        CyclicBarrier cyclicBarrier =
                new CyclicBarrier(NUMBER,()->{
                    System.out.println("*****集齐7颗龙珠就可以召唤神龙");
                });

        //集齐七颗龙珠过程
        for (int i = 1; i <=7; i++) {
            new Thread(()->{
                try {
                    System.out.println(Thread.currentThread().getName()+" 星龙被收集到了");
                    //等待
                    cyclicBarrier.await();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            },String.valueOf(i)).start();
        }
    }
}

7.3 Semaphore

一个计数信号量,从概念上将,信号量维护了一个许可集,如有必要,在许可可用前会阻塞每一个acquire(),然后在获取该许可。每个release()添加一个许可,从而可能释放一个正在阻塞的获取者。但是,不使用实际的许可对象,Semaphore只对可用许可的号码进行计数,并采取相应的行动

具体常用的构造方法有:
Semaphore(int permits)创建具有给定的许可数和非公平的公平设置的Semapore

具体常用的方法有:
acquire()从此信号量获取一个许可,在提供一个许可前一直将线程阻塞,否则线程被中断
release()释放一个许可,将其返回给信号量

设置许可数量Semaphore semaphore = new Semaphore(3);
一般acquire()都会抛出异常,release在finally中执行

通过具体案例
6辆汽车,停3个车位

 

java">//6辆汽车,停3个车位
public class SemaphoreDemo {
    public static void main(String[] args) {
        //创建Semaphore,设置许可数量
        Semaphore semaphore = new Semaphore(3);
        //模拟6辆汽车
        for (int i = 1; i <=6; i++) {
            new Thread(()->{
                try {
                    //抢占
                    semaphore.acquire();
                    System.out.println(Thread.currentThread().getName()+" 抢到了车位");
                    //设置随机停车时间
                    TimeUnit.SECONDS.sleep(new Random().nextInt(5));
                    System.out.println(Thread.currentThread().getName()+" ------离开了车位");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    //释放
                    semaphore.release();
                }
            },String.valueOf(i)).start();
        }
    }
}

 


http://www.niftyadmin.cn/n/1712923.html

相关文章

队列的数组表示

1、队列的结构特点和操作 复习一下队列&#xff1a;数据结构“队列”与我们日常生活中的排队非常相似&#xff0c;按照先到先办的原则办事&#xff0c;并且严格规定不能加塞&#xff0c;也不允许中途离队。 队列&#xff1a;限定只能在队尾进行插入元素&#xff0c;在表头进行…

8. 读写锁

回顾悲观锁和乐观锁的概念悲观锁&#xff1a; 见字知意&#xff0c;他是干什么都很悲观&#xff0c;所以在操作的时候&#xff0c;每次都上锁&#xff0c;使用时解锁乐观锁&#xff1a;他很乐观&#xff0c;多线程&#xff0c;并不上锁&#xff0c;但是会发生 线程安全问题 表…

字符数组与字符指针的理解

1、字符数组 先来想一想什么是字符串&#xff1a; 字符串&#xff08;character string&#xff09;是一个或多个字符的序列&#xff0c;如下所示&#xff1a; “I am a good boy ”双引号不是字符串的一部分。双引号仅告知编译器它括起来的是字符串&#xff0c;正如单引号用于…

图的深度优先遍历和广度优先遍历的实现

1、 图的定义和术语 图&#xff08;grath&#xff09;由一个顶点&#xff08;vertex&#xff09;的有穷非空集合V&#xff08;G&#xff09;和一个弧&#xff08;arc&#xff09;的集合E(G)组成&#xff0c;通常记作G (V,E)。图中的顶点就是数据结构中的数据元素&#xff0c;…

9. 阻塞队列

阻塞队列是共享队列&#xff08;多线程操作&#xff09;&#xff0c;一端输入&#xff0c;一端输出 不能无限放队列&#xff0c;满了之后就会进入阻塞&#xff0c;取出也同理 当队列是空的&#xff0c;从队列中获取元素的操作将会被阻塞 当队列是满的&#xff0c;从队列中添…

数据结构————线性表的实现 合并

1、表的实现 1.1表的数组表示 线性表的定义&#xff1a;线性表是n个元素的有限序列&#xff0c;表中各个数据元素具有相同特性&#xff0c;属于同一数据对象。 #include <stdio.h> #include <stdlib.h>#define TRUE 1 #define FALSE 0 #define OK 1 #define ERR…

10. 线程池

连接池是创建和管理一个连接的缓冲池的技术&#xff0c;这些连接准备好被任何需要它们的线程使用 线程池&#xff08;英语&#xff1a;thread pool&#xff09;一种线程使用模式。线程过多会带来调度开销&#xff0c;进而影响缓存局部性和整体性能。而线程池维护着多个线程&am…

数据结构———插入排序(希尔排序,折半插入,直接插入)

排序 直接插入排序 直接插入排序。对于少量元素的排序&#xff0c;它是一个有效的算法 。插入排序是一种最简单的排序方法&#xff0c;它的基本思想是将一个记录插入到已经排好序的有序表中&#xff0c;从而一个新的、记录数增1的有序表。在其实现过程使用双层循环&#xff0…