并发编程-线程协作工具类

news2025/1/11 15:10:34

工具类概览

在这里插入图片描述
下面我们一个个直接通过案例代码来看我们这些工具类可以用来做什么事情

CountDownLatch

在这里插入图片描述

final CountDownLatch countDownLatch = new CountDownLatch(10);
   final CountDownLatch countDownLatchNoStop = new CountDownLatch(10);
   long startTime = System.currentTimeMillis();
   for (int i = 0; i < 10; i ++) {
       new Thread(() -> {
           try {
               Thread.sleep(1000);
               // 计数器减一
               countDownLatch.countDown();
           } catch (InterruptedException e) {
               throw new RuntimeException(e);
           }
       }).start();
   }
   // 等待所有线程执行完毕
   countDownLatch.await();
   System.out.println("countDownLatch cost time : " + (System.currentTimeMillis() - startTime));
   for (int i = 0; i < 5; i ++) {
       new Thread(() -> {
           try {
               Thread.sleep(1000);
               countDownLatchNoStop.countDown();
           } catch (InterruptedException e) {
               throw new RuntimeException(e);
           }
       }).start();
   }
   countDownLatchNoStop.await();
   // 永远也不会输出 还有五个任务没有执行完
   System.out.println("countDownLatchNoStop cost time : " + (System.currentTimeMillis() - startTime));
}

运行结果:
在这里插入图片描述
我们输出countDownLatch cost time以后永远阻塞了,因为第二个countDownLatchNoStop还没有执行完毕,始终抵达不了await。
因为这个工具类适合分批次去处理任务最后汇总到一起继续执行一段逻辑,比如拼团,比如我们在地图中的层级瓦片生成,1-18每个层级生成成功以后记录成功状态

Semaphore

用来限制或管理数量有限资源的使用情况,也就是用来限流。
在这里插入图片描述

public static void main(String[] args) {
 Semaphore semaphore = new Semaphore(3);
    for (int i = 0; i < 9; i ++) {
        new Thread(() -> {
            try {
                semaphore.acquire();
                System.out.println("当前线程:" + Thread.currentThread().getName());
                TimeUnit.SECONDS.sleep(2);
            } catch (Exception e) {

            } finally {
                semaphore.release();
            }
        }).start();
    }
    new Thread(() ->{
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        System.out.println("------------------------------");
    }).start();

    new Thread(() ->{
        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        System.out.println("------------------------------");
    }).start();
}

在这里插入图片描述
我们可以看到,运行结果哦几乎是3个为一组进行输出,是因为这个工具类定义了就只有三个位置,如果三个位置都满了剩下的线程就只能等待,等到有资源释放了继续执行。

CyclicBarrier

在这里插入图片描述

线程会等待,直到线程到了事先规定的数目,然后触发执行条件进行下一步动作

public static void main(String[] args) {
   final CyclicBarrier barrier = new CyclicBarrier(7, () -> {
       System.out.println("都拿到年终奖了吧,其实刚刚数的都是假钱,怎么可能有给你发年终奖");
       System.out.println("==========================================");
   });
   for (int i = 0; i < 7; i ++) {
       new Thread(() -> {
           System.out.println( "开始给" + Thread.currentThread().getName() +",数10W块钱要数一整子");
           try {
               TimeUnit.SECONDS.sleep(1);
           } catch (InterruptedException e) {
               throw new RuntimeException(e);
           }
           try {
               barrier.await();
               System.out.println(Thread.currentThread().getName() + "哦豁我上当了");
           } catch (InterruptedException e) {
               throw new RuntimeException(e);
           } catch (BrokenBarrierException e) {
               throw new RuntimeException(e);
           }
       }).start();
   }
}

运行结果:
在这里插入图片描述
和CountDownLatch对比,其实前部分的非常的相似,不同的就是CountDownLatch减为0后统一放行,后面的逻辑也是统一了。但是CyclicBarrier就是每个线程执行到栅栏这个地方进行阻塞,然后数量到设定的值以后统一执行一段逻辑,但是之后的逻辑还是分别在各自的线程中执行。

Condition

当线程1需要等待某个条件时就去执行condition.await()方法,一旦执行await()方法,线程就会进入阻塞状态。通常会有另一个线程2去执行对应条件,直到这个条件达成时,线程2就会执行condition.signal()方法,此时JVM就会从被阻塞的线程里找到那些等待该condition的线程,当线程1收到可执行信号时,它的线程状态就会变成Runnable可执行状态。

  • signalAll()会唤起所有正在等待的线程。
  • signal()是公平的,只会唤起那个等待时间最长的线程。
    在这里插入图片描述

下面这个例子是两个线程交替打印:

public class ConditionDemo {
    public static volatile int cnt = 0;
    public static void add() {
        cnt ++;
    }
    public static boolean judge() {
        return cnt == 100;
    }
    public static void main(String[] args) throws InterruptedException {
        Lock lock = new ReentrantLock();
        final Condition c1 = lock.newCondition();
        final Condition c2 = lock.newCondition();
        new Thread(() -> {
            lock.lock();
            try {
                while (!judge()) {
                    add();
                    System.out.println(Thread.currentThread().getName() + "---->" + + cnt);
                    c2.signal();
                    c1.await();
                }
                System.out.println("1 over");
                c2.signal();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            } finally {
                lock.unlock();
            }
        }).start();
        Thread.sleep(100);
        new Thread(() -> {
            lock.lock();
            try {
                while (!judge()) {
                    add();
                    System.out.println(Thread.currentThread().getName() + "---->" + cnt);
                    c1.signal();
                    c2.await();
                }
                System.out.println("2 over");
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            } finally {
                lock.unlock();
            }
        }).start();
    }
}

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1459836.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

jenkins的nmp install命令无法下载包

问题&#xff1a;在jenkin的流水线脚本中执行到&#xff1a;npm install命令后无法下载前端依赖包 1、进到jenkins的工作目录&#xff0c;一般在底层为/var/lib/jenkins/workspace/任务名称 cd /var/lib/jenkins/workspace/xkc处理方式&#xff1a; # 查看镜像源 npm config …

《Solidity 简易速速上手小册》第1章:Solidity 和智能合约简介(2024 最新版)

文章目录 1.1 Solidity 的起源和重要性1.1.1 基础知识解析1.1.2 重点案例&#xff1a;去中心化金融 (DeFi) 平台案例 Demo&#xff1a;简易借贷平台 1.1.3 拓展案例 1&#xff1a;NFT 市场案例 Demo&#xff1a;简易 NFT 市场 1.1.4 拓展案例 2&#xff1a;智能合约管理的投票系…

C语言:数组指针 函数指针

C语言&#xff1a;数组指针 & 函数指针 数组指针数组名 数组访问二维数组 函数指针函数指针使用回调函数 typedef关键字 数组指针 数组本质上也是一个变量&#xff0c;那么数组也有自己的地址&#xff0c;指向整个数组的指针&#xff0c;就叫做数组指针。 我先为大家展示…

stm32——hal库学习笔记(GPIO)

一、GPIO的八种模式分析&#xff08;熟悉&#xff09; GPIO_Mode_IN_FLOATING 浮空输入 GPIO_Mode_IPU 上拉输入 GPIO_Mode_IPD 下拉输入 GPIO_Mode_AIN 模拟输入 GPIO_Mode_Out_OD 开漏输出 GPIO_Mode_Out_PP 推挽输出 GPIO_Mode_AF_OD 复用开漏输出 GPIO_Mode_AF_PP 复用推挽…

springboot+vue的宠物咖啡馆平台(前后端分离)

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、阿里云专家博主、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战&#xff0c;欢迎高校老师\讲师\同行交流合作 ​主要内容&#xff1a;毕业设计(Javaweb项目|小程序|Pyt…

【Linux】自主WEB服务器实现

自主web服务器实现 1️⃣构建TcpServer2️⃣构建HttpServer3️⃣构建HttpRequest和HttpResponseHttp请求报文格式Http相应报文读取、处理请求&构建响应读取请求中的一行读取请求中需要注意的点 4️⃣CGI模式判断是否需要用CGI处理请求构建任务&线程池管理 5️⃣实验结果…

day02_java基础_变量_数据类型等

零、今日内容 1 HelloWorld程序 2 idea使用 3 变量 4 数据类型 5 String 一、复习 班规班纪。。。。。 安装jdk JDK 是开发工具 JRE 是运行代码 JDK包含JRE 配置环境变量 二、HelloWorld程序 前提&#xff1a;JDK已经安装配置完毕&#xff0c;有了这些环境就敲代码 代码…

【Flink精讲】Flink内核源码分析:命令执行入口

官方推荐per-job模式&#xff0c;一个job一个集群&#xff0c;提交时yarn才分配集群资源&#xff1b; 主要的进程&#xff1a;JobManager、TaskManager、Client 提交命令&#xff1a;bin/flink run -t yarn-per-job /opt/module/flink-1.12.0/examples/streaming/SocketWind…

IDEA 2023.2 配置 JavaWeb 工程

目录 1 不使用 Maven 创建 JavaWeb 工程 1.1 新建一个工程 1.2 配置 Tomcat 1.3 配置模块 Web 2 使用 Maven 配置 JavaWeb 工程 2.1 新建一个 Maven 工程 2.2 配置 Tomcat 1 不使用 Maven 创建 JavaWeb 工程 1.1 新建一个工程 建完工程后&#xff0c;还要加入 Modules …

基于springboot校园志愿者管理系统源码和论文

随着信息化时代的到来&#xff0c;管理系统都趋向于智能化、系统化&#xff0c;校园志愿者管理系统也不例外&#xff0c;但目前国内仍都使用人工管理&#xff0c;市场规模越来越大&#xff0c;同时信息量也越来越庞大&#xff0c;人工管理显然已无法应对时代的变化&#xff0c;…

NFC物联网在互联家庭的应用

现今越来越多的家庭接入网络。日常家居甚至像灯、吊扇、恒温器等物件也可连接到互联网&#xff0c;使用基于互联网的协议和硬件来控制。物联网&#xff08;IoT&#xff0c;即越来越多的物品相连的互联网&#xff09;&#xff0c;正在重新定义我们居家的环境&#xff0c;并创造新…

MySQL初识——安装配置

文章目录 1. MySQL卸载2. 获取MySQL官方yum源安装包3. 安装4. 启动MySQL5. 登录6. 配置配置文件 Tips&#xff1a; 本章是Centos 7安装配置myql&#xff0c;配置操作用的是root权限 1. MySQL卸载 首先我们先查看一下系统中是否有mysql服务 ps axj | grep mysql如果有&#xf…

人工智能|深度学习——基于数字图像处理和深度学习的车牌定位

1.研究背景及研究目的和意义 车牌识别Vehicle License Plate Recognition VLPR) 是从一张或一系列数字图片中自动定位车牌区域并提取车牌信息的图像识别技术。车牌识别 以数字图像处理、模式识别、计算机视觉等技术为基础&#xff0c;是现代智能交通系统的重要组成部分&#xf…

QEMU源码全解析 —— virtio(20)

接前一篇文章&#xff1a; 上回书重点解析了virtio_pci_modern_probe函数。再来回顾一下其中相关的数据结构&#xff1a; struct virtio_pci_device struct virtio_pci_device的定义在Linux内核源码/drivers/virtio/virtio_pci_common.h中&#xff0c;如下&#xff1a; /* O…

【Spring】IoC容器 控制反转 与 DI依赖注入 XML实现版本 第二期

文章目录 基于 XML 配置方式组件管理前置 准备项目一、 组件&#xff08;Bean&#xff09;信息声明配置&#xff08;IoC&#xff09;&#xff1a;1.1 基于无参构造1.2 基于静态 工厂方法实例化1.3 基于非静态 工厂方法实例化 二、 组件&#xff08;Bean&#xff09;依赖注入配置…

【经验分享】分类算法与聚类算法有什么区别?白话讲解

经常有人会提到这个问题&#xff0c;从我个人的观点和经验来说2者最明显的特征是&#xff1a;分类是有具体分类的数量&#xff0c;而聚类是没有固定的分类数量。 你可以想象一下&#xff0c;分类算法就像是给你一堆水果&#xff0c;然后告诉你苹果、香蕉、橙子分别应该放在哪里…

MKS射频RF电源Elite系列匹配器MW-2513功能电源操作使用说明中文

MKS射频RF电源Elite系列匹配器MW-2513功能电源操作使用说明中文

代码随想录算法训练营第二十三天 | 669. 修剪二叉搜索树,108.将有序数组转换为二叉搜索树,538.把二叉搜索树转换为累加树 [二叉树篇]

代码随想录算法训练营第二十三天 LeetCode 669. 修剪二叉搜索树题目描述思路递归参考代码 LeetCode 108.将有序数组转换为二叉搜索树题目描述思路参考代码 LeetCode 538.把二叉搜索树转换为累加树题目描述思路参考代码 LeetCode 669. 修剪二叉搜索树 题目链接&#xff1a;669. …

认识K8S

K8S K8S 的全称为 Kubernetes (K12345678S) 是一个跨主机容器编排工具 作用 用于自动部署、扩展和管理“容器化&#xff08;containerized&#xff09;应用程序”的开源系统。 可以理解成 K8S 是负责自动化运维管理多个容器化程序&#xff08;比如 Docker&#xff09;的集群…

Android Studio基础(下载安装与简单使用)

1、搭建Android开发平台 1.1 Android Studio 下载地址及版本说明 Android 开发者官网&#xff1a; https://developer.android.com/index.html&#xff08;全球&#xff0c;需科学上网&#xff09; https://developer.android.google.cn/index.html&#xff08;国内&#xff…