JUC【Callable、ReentrantLock、Semaphore、CountDownLatch】

news2025/1/18 3:41:59

JUC ==> java.util.concurrent

JUC标准库提供的多线程安全相关的包

Callable 接口声明带返回值的任务

类似于Runnable,都是用来描述这个线程的工作的。

Callable描述的任务带返回值,Runnable描述的任务不带返回值

区别:线程封装了一个 “返回值”,Runnable没有返回值。

搭配FutureTask使用

代码示例: 创建线程计算 1 + 2 + 3 + … + 1000,返回结果

public static void main(String[] args) throws InterruptedException, ExecutionException {
        //创建Callable任务
        Callable<Integer> callable = new Callable<Integer>() {
            //call方法描述的是整个线程的任务,带有返回值
            @Override
            public Integer call() throws Exception {
                int sum = 0;
                for(int i = 1; i <= 100; i++) {
                    sum += i;
                }
                return sum;
            }
        };
        //想要拿到callable里面的返回值,必须创建FutureTask对象
        FutureTask<Integer> futureTask = new FutureTask<>(callable);
        Thread t = new Thread(futureTask);
        t.start();
        int result = futureTask.get();
        System.out.println(result);
    }
  • 创建一个匿名内部类, 实现 Callable 接口. Callable 带有泛型参数. 泛型参数表示返回值的类型.
  • 重写 Callable 的 call 方法, 完成累加的过程. 直接通过返回值返回计算结果.
  • 把 callable 实例使用 FutureTask 包装一下.
  • 创建线程, 线程的构造方法传入 FutureTask . 此时新线程就会执行 FutureTask 内部的 Callable 的
  • 启动线程执行call 方法, 完成计算. 计算结果就放到了 FutureTask 对象中.
  • 在主线程中调用 futureTask.get() 能够阻塞等待新线程计算完毕. 并获取到 FutureTask 中的结果.

FutureTask类似于票根,你得拿着它才能查询到结果。

ReentrantLock

可重入互斥锁. 和 synchronized 定位类似, 都是用来实现互斥效果, 保证线程安全.

核心方法:

1、lock()加锁

2、unlock()解锁

3、tryLock() 尝试加锁,能加就加,加不了就算了

缺点:

容易遗漏unlock操作:使用lock()和unlock()时候,有可能中途碰到return语句,unlock还没执行到就返回了。

ReentrantLock locker = new ReentrantLock();
//加锁
lokcer.lock();
//任务 [有可能return]

//解锁
locker.unlock();

解决办法: 使用try finally

ReentrantLock locker = new ReentrantLock();
        try {
        	//加锁
            locker.lock();
            //任务
        } finally {
        	//解锁
            locker.unlock();
        }
    }

优点:

1、tryLock 是尝试加锁,能加上就加,加不上就放弃,其中tryLock还可以设置加锁的等待(尝试)时间

2、ReentrantLock还可以实现公平锁,默认是非公平
构造的时候传染一个参数就是公平锁

ReentrantLock locker = new ReentrantLock(true);

3、synchronized是搭配wait/notify实现等待通知机制,notify唤醒操作是随机唤醒一个等待的线程;

ReentrantLock是搭配Condition类实现的,唤醒操作是可以指定唤醒哪个等待的线程

【面试题】说说synchronized和ReentrantLock的区别

区别 = 缺点 +优点

  • synchronized 是一个关键字, 是 JVM 内部实现的. ReentrantLock 是标准库的一个类, 在 JVM 外实现的(基于 Java 实现).
  • synchronized 使用时不需要手动释放锁. ReentrantLock 使用时需要手动释放. 使用起来更灵活, 但是也容易遗漏 unlock.
  • synchronized 在申请锁失败时, 会死等. ReentrantLock 可以通过 trylock 的方式等待一段时间就放弃.
  • synchronized 是非公平锁, ReentrantLock 默认是非公平锁. 可以通过构造方法传入一个 true 开启公平锁模式.
  • synchronized 是通过 Object 的 wait / notify 实现等待-唤醒. 每次唤醒的是一个随机等待的线程. ReentrantLock 搭配 Condition 类实现等待-唤醒, 可以更精确控制唤醒某个指定的线程.

原子类

原子类内部用的是 CAS 实现,所以性能要比加锁实现 i++ 高很多。

原子类应用

使用原子类,最常见的就是多线程奇数。写了个服务器,服务器一共有多少个并发了,就可以通过原子变量来累加。

  • AtomicBoolean
  • AtomicInteger
  • AtomicIntegerArray
  • AtomicLong
  • AtomicReference
  • AtomicStampedReference

以 AtomicInteger 举例,常见方法有:

addAndGet(int delta); i += delta;

decrementAndGet(); --i;

getAndDecrement(); i–;

incrementAndGet(); ++i;

getAndIncrement(); i++;

ThreadPoolExcutor线程池

之前讲过,不赘述

信号量Semaphore

信号量的基本操作:

P操作 :申请一个资源

V操作:释放一个资源

PV 操作中的加减计数器操作都是原子的, 可以在多线程环境下直接使用

信号量本质—计数器

信号量本身是一个计数器,表示可用资源的个数

P操作申请一个资源,可用资源数-1;

V操作,释放一个资源,可用资源数+1;

当奇数为0时候继续P操作,就会阻塞,阻塞等待到其他线程V操作为止。(生产者消费者模型)

信号量是广义的锁

锁就是一个特殊的信号量(可用资源只有1的信号量)

代码示例

创建 Semaphore 示例, 初始化为 4, 表示有 4 个可用资源. acquire 方法表示申请资源(P操作), release 方法表示释放资源(V操作)

public static void main(String[] args) throws InterruptedException {

        Semaphore semaphore = new Semaphore(4);
        semaphore.acquire();
        System.out.println("申请资源1");
        semaphore.acquire();
        System.out.println("申请资源2");
        semaphore.acquire();
        System.out.println("申请资源3");
        semaphore.acquire();
        System.out.println("申请资源4");
        semaphore.acquire();
        System.out.println("申请资源5");
        semaphore.release();
        System.out.println("释放资源");
}

执行效果:

image-20230228204807942

在执行到第四个申请资源以后,代码就阻塞了,原因是一开始的资源就只有4个,在前面已经全部被P操作申请完了,要想再申请,只能等待其他线程的V操作释放资源,所以进行阻塞等待。

CountDownLatch

同时等待 N 个任务执行结束.

举例:跑步比赛,10个选手依次就位,哨声响才同时出发;所有选手都通过终点,才算比赛结束

使用CoutDownLatch就是类似的效果,使用的时候先设置有多少个选手,然后每个选手到达了重点,调用countDown方法,当到达重点的人数到达了先前设置的人数,比赛就认为结束了。

public static void main(String[] args) throws InterruptedException {
    CountDownLatch latch = new CountDownLatch(10);
    for (int i = 0; i < 10; i++) {
        //10个选手 相当于10个进程
        Thread t = new Thread(()->{
            System.out.println("开始执行任务:" + Thread.currentThread().getName());
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println("结束执行任务" + Thread.currentThread().getName());
            //到达终点
            latch.countDown();
        });
        t.start();
    }
    latch.await();
    System.out.println("比赛结束");
}
  • 构造 CountDownLatch 实例, 初始化 10 表示有 10 个任务需要完成.
  • 每个任务执行完毕, 都调用 latch.countDown() . CountDownLatch 内部的计数器同时自减.
  • 主线程中使用 latch.await(); 阻塞等待所有任务执行完毕. 相当于计数器为 0 了.

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

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

相关文章

【项目精选】基于网络爬虫技术的网络新闻分析(视频+论文+源码)

点击下载源码 基于网络爬虫技术的网络新闻分析主要用于网络数据爬取。本系统结构如下&#xff1a; &#xff08;1&#xff09;网络爬虫模块。 &#xff08;2&#xff09;中文分词模块。 &#xff08;3&#xff09;中3文相似度判定模块。 &#xff08;4&#xff09;数据结构化存…

【Python - Matplotlib】P2 plot 折线图

Matplotlib绘制折线图折线图完整代码与效果基础折线图设定横纵坐标设置中文显示添加网格添加描述信息再添加一个城市设置两个折线图前言 上一节内容主要围绕介绍 Matplotlib 的画板结构。 链接&#xff1a;https://blog.csdn.net/weixin_43098506/article/details/129331576 本…

云HIS系统 云his系统源码 基于电子病历的医院信息平台标准建设

云HIS系统 云his系统源码 基于电子病历的医院信息平台标准进行建设 云HIS系统采用SaaS软件应用服务模式&#xff0c;提供软件应用服务多租户机制&#xff0c;实现一中心部署多机构使用。相对传统HIS单机构应用模式&#xff0c;它可灵活应对区域医疗、医疗集团、医联体、连锁诊…

GB28181国标平台LiveGBS视频统一汇聚后如何获取固定的播放地址,实现监控视频Web页面无插件播放、拉流分析、上大屏等目的...

目前汇聚各种厂家监控设备的视频汇聚平台&#xff0c;基本都是通过GB28181标准协议实现的。下面介绍下LiveGBS Web无插件直播的GB28181视频平台将各厂家(包括海康、大华、华为、宇视、天地伟业等)监控汇聚到同一个服务器上后&#xff0c;如何或者直播链接可以直播浏览器播放&am…

flstudio21水果language选项中文设置方法教程

编曲是通过DAW&#xff08;数字音频工作站软件&#xff09;完成的&#xff0c;也就是我们常说的宿主软件。现在有很多优秀的宿主软件&#xff0c;例如Cubase、Studio One、FL Studio等。 FL Studio是一款功能强大的音乐制作软件&#xff0c;也被称为FruityLoops。目前已经推出…

Android上传手机图片到服务器(这篇你要是看不懂,全网没你可以看懂的了!!!)

Android上传手机图片到服务器1、整体流程2、页面布局3、选择图片流程实现演示结果完整代码4、路径转换路径转换Utils工具类权限申请完整代码5、创建文件6、服务器端7、传输8、演示9、完整代码目录结构AndroidManifest.xml布局文件activity_main.xml传输文件工具类HttpUtil路径转…

蓝桥杯-质因数个数

蓝桥杯-质因数个数1、问题描述2、解题思路2.1 质数判断2.2 求取因子3、完整代码实现1、问题描述 给定正整数 n, 请问有多少个质数是 n 的约数。 输入格式 输入的第一行包含一个整数 n。 输出格式 输出一个整数, 表示 n 的质数约数个数。 样例输入 396样例输出 3样例说明 3…

【教学典型案例】13.学情页面逻辑问题

目录一&#xff1a;背景介绍二&#xff1a;LocalStorage缓存①localStorage是什么&#xff1f;②如何使用localStorage缓存三&#xff1a;学情页面逻辑分析过程四&#xff1a;总结五&#xff1a;升华一&#xff1a;背景介绍 使用的前端技术是Vue2&#xff0c;前端逻辑&#xf…

SpringCloud:Eureka

目录 一、eureka的作用 二、搭建Eureka服务端 三、添加客户端 四、服务发现 提供者与消费者 服务提供者&#xff1a;一次业务中&#xff0c;被其它微服务调用的服务。&#xff08;提供接口给其它微服务) 服务消费者&#xff1a;一次业务中&#xff0c;调用其它微服务的服…

[1.1_2]计算机系统概述——操作系统的四个特征

文章目录第一章 计算机系统概述操作系统的特征&#xff08;一&#xff09;并发&#xff08;二&#xff09;共享并发和共享的关系&#xff08;三&#xff09;虚拟&#xff08;四&#xff09;异步小结第一章 计算机系统概述 操作系统的特征 操作系统的四个特征 并发共享 并发和共…

Linux学习第七节-SUID、SGID、SBIT特殊权限

1.SetUID特殊权限 setUID (SUID): 对于一个可执行的文件使用SUID权限后&#xff0c;普通用户在执行改文件后&#xff0c;临时拥有文件所有者的身份&#xff0c;该权限只在程序执行过程中有效&#xff0c;程序执行完毕后用户恢复原有身份。 SetUID权限会附加在所有者的x权限位上…

每日分享(2023最新文件快递柜系统网站源码 匿名口令分享临时文件分享)

​demo软件园每日更新资源,请看到最后就能获取你想要的: 1.UML参考手册(第二版) 中文 中文名: UML参考手册&#xff08;第二版&#xff09;原名: The Unified Modeling Language Reference Manual(2nd Edition) 作者: James Rumbaugh Ivar Jacobson Grady Booch译者: UML Ch…

汇编语言程序设计(二)之寄存器

系列文章 汇编语言程序设计&#xff08;一&#xff09; 寄存器 在学习汇编的过程中&#xff0c;我们经常需要操作寄存器&#xff0c;那么寄存器又是什么呢&#xff1f;它是用来干什么的&#xff1f; 它有什么分类&#xff1f;又该如何操作&#xff1f;… 你可能会有许多的…

基于PySide6的MySql数据库快照备份与恢复软件

db-camera 软件介绍 db-camera是一款MySql数据库备份&#xff08;快照保存&#xff09;与恢复软件。功能上与dump类似&#xff0c;但是提供了相对有好的交互界面&#xff0c;能够有效地管理导出的sql文件。 使用场景 开发阶段、测试阶段&#xff0c;尤其适合单人开发的小项目…

降低物联网开发门槛的神器大更新!TuyaOS 3.7.0版本新增matter等开发框架

作为降低物联网开发门槛的TuyaOS &#xff0c;此次迎来了重大更新&#xff08;点击查看TuyaOS 往期介绍&#xff09;&#xff01;TuyaOS 3.7.0 新版本不仅支持多款 Matter 开发框架&#xff0c;帮助开发者轻松奔赴万物互联时代&#xff0c;还覆盖多种协议连接&#xff0c;能快速…

【Simulink】单相电压型全桥逆变电路仿真基础实验

版本&#xff1a;matlab2019b 1 单相电压型全桥逆变电路简介 1.1 逆变 逆变&#xff0c;即直流变换成交流。 在全桥逆变电路中&#xff1a;V1、V2、V3、V4 为 IGBT&#xff0c;VD1、VD2、VD3、VD4为二极管 当V1、V4导通&#xff0c;V2、V3截止时&#xff0c;负载电压uo为正&a…

【CV学习笔记】之ncnnFastDet多线程c++部署

1、前言 ncnn是一款非常高效易用的深度学习推理框架&#xff0c;支持各种神经网络模型&#xff0c;如pytorch、tensorflow、onnx等&#xff0c;以及多种硬件后端&#xff0c;如x86、arm、riscv、mips、vulkan等。 ncnn项目地址:https://github.com/Tencent/ncnn FastDet是设计…

English Learning - L2 第2次小组纠音 [iː] [ɜː] [æ] 2023.3.1 周三

English Learning - L2 第2次小组纠音 [iː] [ɜː] [] 2023.3.1 周三共性问题分析前元音 [iː]中元音 [ɜː]前元音 []我的发音问题舌位找的不准纠音过程共性问题分析 前元音 [iː] 嘴角左右拉伸没有到位 解决方法&#xff1a; 嘴角是往耳后根的方向&#xff0c;微微上扬的角…

指针和数组面试题(逐题分析,完善你可能遗漏的知识)

人生不是一种享乐&#xff0c;而是一桩十分沉重的工作。 —— 列夫托尔斯泰 前言&#xff1a;之前我们就学习了数组和指针的知识。 数组&#xff1a;数组就是能够存放一组相同类型的元素&#xff0c;数组的大小取决于数组的元素个数和元素类型。 指针&#xff1a;…

Linux操作系统学习(进程等待)

文章目录进程等待进程等待的必要性如何进程等待waiwaitpid验证进程等待 ​ 我们知道fork函数可以创建一个子进程&#xff0c;而子进程通常是替父进程完成一些任务&#xff0c;而父进程在fork之后需要通过wait/waitpid等待子进程退出。这就是进程等待 进程等待的必要性 通过获…