• JUC并发编程——常用的辅助类(基于狂神说的学习笔记)


    常用的辅助类

    countDownLatch

    减法计数器

    本质上是等待一系列线程完成它的任务的计数工具

    允许一个或多个线程等待直到在其他线程中执行的一组操作完成的同步辅助。

    使用给定计数初始化CountDownLatch 。 所述await方法阻塞,直到当前计数达到零由于的调用countDown()方法,之后所有等待的线程被释放和任何后续调用await立即返回。 这是一次性现象 - 计数无法重置。 如果您需要重置计数的版本,请考虑使用CyclicBarrier

    CountDownLatch是一种多功能同步工具,可用于多种用途。 初始化为计数为1的CountDownLatch用作简单的开/关锁存器或门:所有调用await线程在门等待,直到由调用countDown()的线程打开它。 初始化为NCountDownLatch可用于使一个线程等待,直到N个线程完成某个动作,或者某个动作已完成N次。

    CountDownLatch一个有用属性是它不需要调用countDown线程等待计数在继续之前达到零,它只是阻止任何线程继续通过await直到所有线程都可以通过。

    **示例用法:**这是一对类,其中一组工作线程使用两个倒计时锁存器:

    • 第一个是启动信号,阻止任何工人继续工作,直到驱动程序准备好继续进行;
    • 第二个是完成信号,允许驾驶员等到所有工人完成。

    实例:

    package callable;
    
    import java.util.concurrent.CountDownLatch;
    
    // 计数器
    public class CountDownLatchDemo {
        public static void main(String[] args) throws InterruptedException {
            // 倒计时,总数是六, 必须要执行任务的时候再使用
            CountDownLatch countDownLatch = new CountDownLatch(6);
    
            for (int i = 0; i < 6; i++) {
                new Thread(()->{
                    System.out.println(Thread.currentThread().getName()+" go out");
                    countDownLatch.countDown();// -1操作
                },String.valueOf(i)).start();
            }
    
            countDownLatch.await(); // 等待计数器归零,然后再向下执行;
    
            System.out.println("close the door");
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    原理:

    countDownLatch.countDown(); // 数量-1

    coutnDownLatch.await(); // 等待计数器归零,然后再向下执行

    每次线程调用countDown()数量-1,假设计数器变为0,countDownLatch.await()就会被唤醒,继续执行

    CyclicBarrier

    加法计数器

    一种同步辅助工具,允许一组线程全部等待彼此到达公共障碍点。 CyclicBarriers在涉及固定大小的线程方的程序中很有用,这些线程必须偶尔等待彼此。 屏障称为*循环,*因为它可以在释放等待线程后重新使用。

    CyclicBarrier支持可选的Runnable命令,该命令在每个障碍点运行一次,在聚会中的最后一个线程到达之后,但在释放任何线程之前。 在任何一方继续之前,此屏障操作对于更新共享状态非常有用。

    package add;
    
    import java.util.concurrent.BrokenBarrierException;
    import java.util.concurrent.CyclicBarrier;
    
    public class CycliBarrierDemo {
        public static void main(String[] args) {
            /**
             * 集齐七颗龙珠召唤神龙
             */
            // 召唤龙珠的线程
            // 有两个参数,第一个为数量,第二个为达到数量后开启的线程,直接使用runnable接口的lambda表达式
            CyclicBarrier cyclicBarrier = new CyclicBarrier(7,()->{
                System.out.println("召唤神龙,成功");
            });
    
            for (int i = 1; i <= 7; i++) {
                final int temp = i;
                // lambda 能操作到 i 吗? ----> 不行,因为lambda表达式本质上是new了一个对象,实现了接口方法
                new Thread(()->{
                    System.out.println(Thread.currentThread().getName()+"收集了"+temp+"颗");
    
                    try {
                        cyclicBarrier.await();// 等待
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    } catch (BrokenBarrierException e) {
                        throw new RuntimeException(e);
    
                    }
                }).start();
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    Semaphore

    信号量

    作用:

    实现多个线程互斥地使用共享资源,并发限流,控制最大的线程数

    原理:

    acquire()方法,使线程获得资源,每有一个线程获得资源,信号量-1,若信号量为0,则剩余线程等待

    release()方法,释放,会将当前的信号量释放并+1,然后唤醒等待的线程

    new Semaphore(3); // 限定三个线程并发工作

    semaphore.acquire(); // 让一个线程得到资源开始工作

    semaphore.release(); // 释放当前抢占资源的线程,如果还有线程等待工作,换下一个线程进来

    注:(来自文心一言)

    semaphore.acquire() 操作是尝试获取一个或多个信号量。具体取决于你调用 acquire() 方法时传递的参数。

    如果你调用 semaphore.acquire(n),其中 n 是你希望获取的信号量数量,那么它会尝试一次性获取 n 个信号量。如果当前可用的信号量数量少于 n,那么这个操作将会阻塞,直到有足够的信号量可用。

    如果你调用 semaphore.acquire() 并且不提供任何参数,那么它会尝试获取一个信号量。如果当前没有可用的信号量,那么这个操作也将会阻塞,直到有一个信号量可用。

    总的来说,semaphore.acquire() 可以在一次调用中尝试获取一个或多个信号量,具体取决于你如何调用它。但是,它的行为并不是“一次性将所有信号量都分配完毕”,而是根据你传递的参数来决定获取多少个信号量。

    package add;
    
    import java.util.concurrent.Semaphore;
    import java.util.concurrent.TimeUnit;
    
    public class SemaphoreDemo {
        public static void main(String[] args) {
            // 参数:线程数量
            // 限流的情况下可以使用
            // 让线程有序地进行工作
            Semaphore semaphore = new Semaphore(3);
            for (int i = 1; i <= 6; i++) {
                new Thread(()->{
                    try {
                        semaphore.acquire();// acquire() 得到
                        System.out.println(Thread.currentThread().getName()+"抢到车位");
                        TimeUnit.SECONDS.sleep(2);
                        System.out.println(Thread.currentThread().getName()+"离开车位");
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }finally {
                        semaphore.release();// release() 释放
                    }
    
                },String.valueOf(i)).start();
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
  • 相关阅读:
    若依前后端分离发布富文本框内容 | uni-app微信小程序展示富文本框内容
    记一次高校学生账户的“从无到有”
    luming.02无限进步 #我的创作纪念日
    为了追学姐,用python把她的照片做成了游戏,她看了...
    ThreadLocal
    常用数据结构 ——— 队列(环形队列和顺序队列)
    HTML期末大作业——游戏介绍(HTML+CSS+JavaScript) web前端开发技术 web课程设计网页规划与设计 Web大学生网页成品
    JAVAEE:采用HTML和JavaScript实现几个基本的页面
    什么是电商云仓?
    白酒行业数字化转型| 酒业中秋营销指南
  • 原文地址:https://blog.csdn.net/whale_cat/article/details/133827810