多线程—JUC(java.util.concurrent)
上篇文章:
多线程—synchronized原理
https://blog.csdn.net/sniper_fandc/article/details/146713129?fromshare=blogdetail&sharetype=blogdetail&sharerId=146713129&sharerefer=PC&sharesource=sniper_fandc&sharefrom=from_link
目录
1 Callable接口
2 ReentrantLock
3 原子类
4 线程池
5 信号量Semaphore
6 CountDownLatch
1 Callable接口
在多线程环境下,如果要计算1+...+100的值,没有学习Callable接口前,可能我们写的代码如下:
public class CallThread {public static Object locker = new Object();public static int sum = 0;public static void main(String[] args) throws InterruptedException {Thread t = new Thread(() -> {int result = 0;for(int i = 1;i <= 100;i++){result += i;}synchronized (locker){sum = result;locker.notify();}});t.start();synchronized (locker){while(sum == 0){locker.wait();}System.out.println("1+...+100 = " + sum);}}}
由于run方法没有返回值,因此必须使用全局变量sum来接收计算结果,同时要输出计算结果,必须得等线程运行结束,因此使用wait和notify方法来保证线程同步。这样的代码是比较繁琐的,如果使用了Callable接口,就会简化很多:
public class CallThread {public static void main(String[] args) throws InterruptedException, ExecutionException {Callable<Integer> callable = new Callable<Integer>() {public Integer call() throws Exception {int result = 0;for(int i = 1;i <= 100;i++){result += i;}return result;}};FutureTask<Integer> futureTask = new FutureTask<>(callable);Thread t = new Thread(futureTask);t.start();System.out.println("1+...+100 = " + futureTask.get());}}
上述代码的运行结果如下:

Callable接口类似Runnable接口,也是定义线程需要执行的任务,但是不同的是这个任务可以带返回值,返回值类型就是泛型参数类型。定义任务后,需要用FutureTask来包装这个任务,用于接收Callable实例的返回值。创建线程需要把FutureTask的实例作为参数传入,线程执行结束后,会把计算结果放入FutureTask的实例中。获取FutureTask实例中的返回值需要用到get(),如果线程还没有执行结束,代码会阻塞到get()方法的位置,直到线程执行结束接收到返回值。
2 ReentrantLock
ReentrantLock直译可重入锁,和synchronized类似,也是通过加锁实现共享数据的互斥访问。
ReentrantLock类加锁操作的实现方式是通过ReentrantLock的实例.lock()来加锁,通过ReentrantLock的实例.unlock()来解锁:
ReentrantLock lock = new ReentrantLock();lock.lock();... lock.unlock();
但是这种方式往往给开发人员带来更复杂的代码逻辑,导致如果加锁过程中出现异常,可能程序就执行不到解锁,因此常常搭配try-catch-finally语句使用:
ReentrantLock lock = new ReentrantLock();lock.lock(); try { ...} finally { lock.unlock() }
有了synchronized,为什么还需要ReentrantLock?(它们的区别是什么)
1.synchronized是关键字,是JVM内部的实现。而ReentrantLock是一个类,是标准库的一个类,是基于java的实现。
2.synchronized的加锁解锁基于代码块,进入代码块加锁,退出代码块解锁,不需要显示调用加锁解锁的代码。ReentrantLock的加锁解锁基于lock()和unlock(),需要显示调用方法,更灵活,但是解锁容易遗漏。
3.synchronized是非公平锁。而ReentrantLock默认是非公平锁,但是也提供了公平锁版本,构造方法传参true就会启用公平锁策略。
4.synchronized如果加锁失败,就会进入阻塞状态。而ReentrantLock提供trylock()方法,这个方法会尝试加锁,如果加锁失败,不会进入阻塞状态并返回false,继续向下执行其他代码。trylock()还可以设置一定的等待时间,如果加锁失败,就等待一会,时间一过再放弃。
5.synchronized必须使用wait()和notify()来等待和唤醒,唤醒时随机唤醒一个线程。ReentrantLock搭配Condition类实现等待和唤醒,可以随机唤醒一个,也可以唤醒指定线程。
当锁竞争不激烈时,使用synchronized更好(偏向锁和轻量级锁)。当锁竞争激烈时,使用ReentrantLock更灵活,不让线程死等。如果想要使用公平锁,也要用ReentrantLock。
3 原子类
原子类基于CAS实现,因此比加锁实现的代码性能更高,主要有以下几个类:AtomicBoolean、AtomicInteger、AtomicIntegerArray、AtomicLong、AtomicReference、AtomicStampedReference。
常见的方法有:addAndGet(int delta)<=>i += delta、decrementAndGet()<=>--i、getAndDecrement()<=>i--、incrementAndGet()<=>++i、getAndIncrement()<=>i++,这些方法都是AtomicInteger类中的方法。
4 线程池
线程池的创建最核心的类是ThreadPoolExecutor类,这个类有多种参数,帮助我们创建多种类型的线程池:
corePoolSize:核心线程的数量。(核心线程一旦创建就一直存在)
maximumPoolSize:最大线程的数量=核心线程+临时线程的数目。(临时线程:一段时间不干活,就被销毁)
keepAliveTime:临时线程允许的空闲时间。
unit:keepaliveTime的时间单位,是秒,分钟等等。
workQueue:传递任务的阻塞队列。线程池内部有默认的阻塞队列,我们也可以传入自定义的队列。(线程池的可扩展性)
threadFactory:创建线程的工厂,参与具体的创建线程工作。
RejectedExecutionHandler:拒绝策略,如果任务量超出线程池的任务队列的负荷了接下来怎么处理。策略有如下四种:
AbortPolicy():超过负荷,直接抛出异常。
CallerRunsPolicy():调用者负责处理。
DiscardOldestPolicy():丢弃队列中最老的任务。
DiscardPolicy():丢弃新来的任务。
而前面使用线程池创建线程方法中使用的Executors本质上是ThreadPoolExecutor类的封装。
注意:创建线程池时线程数量如何设置?但凡回答具体的数字都是错的,正确的做法是根据不同的程序设置不同数量,可以通过压测(性能测试)来控制不同线程数量,观察CPU占用率、内存占用率等等来确定合适的线程数量。
5 信号量Semaphore
信号量Semaphore表示可用资源的数量,本质上是一个计数器,在信号量机制中有操作P和V(都是原子性的操作),P操作表示申请资源,因此P操作后资源数量-1;V操作表示释放资源,V操作后资源数量+1。当可用资源数量为0时,P操作阻塞,因此通过信号量机制也可以实现线程同步。
P操作对应的方法是acquire(),V操作对应的方法是release()。具体使用如下:
public class MySemaphore {public static void main(String[] args) throws InterruptedException {Semaphore semaphore = new Semaphore(3);semaphore.acquire();System.out.println("获取资源");semaphore.acquire();System.out.println("获取资源");semaphore.acquire();System.out.println("获取资源");// semaphore.release();// System.out.println("释放资源");semaphore.acquire();System.out.println("获取资源");}}
创建包含3个资源的计数器,但是main尝试连续获取4个资源,结果是被阻塞到第4次acquire()处。

如果把代码中的注释取消,即连续3次获取资源,此时可用资源的数量为0,再释放一次资源,此时可用资源的数量为1,再获取1次资源即可顺利执行。

6 CountDownLatch
CountDownLatch这个类会等待所有的任务都执行结束后再执行后续的代码,具体使用如下:
public class CountDownLatchDemo {public static void main(String[] args) throws InterruptedException {CountDownLatch countDownLatch = new CountDownLatch(10);for(int i = 0;i < 10;i++){Thread t = new Thread(() ->{try {//Math.random()返回0-1之间的随机数Thread.sleep((long)(Math.random() * 5000));System.out.println(Thread.currentThread().getName() + "执行完毕了");countDownLatch.countDown();} catch (InterruptedException e) {e.printStackTrace();}},"线程"+ i);t.start();}countDownLatch.await();System.out.println("所有任务都执行完了,工作结束");}}
CountDownLatch的构造方法传入的参数表示任务的个数,对应内部有个计数器,每当一个任务调用countDownLatch.countDown(),计数器-1。await()会进行阻塞,直到计数器为0。只有所有任务都调用countDown(),计数器为0,所有任务都执行完毕,此时await()方法才结束阻塞。代码运行结果如下:

下篇文章:
相关文章:
多线程—JUC(java.util.concurrent)
上篇文章: 多线程—synchronized原理https://blog.csdn.net/sniper_fandc/article/details/146713129?fromshareblogdetail&sharetypeblogdetail&sharerId146713129&sharereferPC&sharesourcesniper_fandc&sharefromfrom_link 目录 1 Calla…...
软件工程面试题(十二)
1、文件和目录(i/o)操作,怎么列出某目录下所有文件?某目录下所有子目录,怎么判断文件或目录是否存在?如何读写文件? 列出某目录下所有文件:调用listFile(),然后判断每个File对象是否是文件可以调用 isFile(),判断是否是文件夹可以调用isDirectory(),判断文件或目…...
从零开始跑通3DGS教程:(三)坐标系与尺度编辑(CloudCompare)
写在前面 本文内容 本文所属《从零开始跑通3DGS教程》系列文章; sfm重建的点云已经丢掉了尺度信息,并且坐标系跟图像数据有关(SFM初始化选择的图像),所以如果想恢复物理真实尺度,以及在想要的视角下渲染,那么需要对尺度…...
多线程 - 线程安全引入
写一个代码,让主线程创建一个新的线程,由新的线程负责完成一系列的运算(比如:1 2 3 ... 1000),再由主线程负责获取到最终结果。 但打印结果为 result 0,略微思考,明白了要让 t 线…...
笔记:基于环境语义的通感融合技术,将传统通信由“被动接收”转为“主动感知”
《基于计算机视觉的感知通信融合理论与关键技术研发进展》 介绍了联合研发的基于环境语义的通感融合技术研发进展。 观点:利用环境感知信息或环境语义辅助通信的通感融合技术成为6G重要方向之一 产出:基于环境感知的毫米波波束管理方案,并…...
【面试八股】:CAS指令
一、CAS 面试题 1. 说说CAS、CAS有什么问题(ABA)?(美团一面) Compare And Swap 对比交换(原子指令) CAS是 CPU指令 操作系统原生 API,JVM对它进行了封装(C),供我们使用。 通过判断 内存 和 …...
matplot显示中文
import matplotlib.pyplot as plt from matplotlib.font_manager import FontProperties 指定字体文件路径 font_path ‘/usr/share/fonts/SIMHEI.TTF’ font_prop FontProperties(fnamefont_path) 示例代码 plt.plot([1, 2, 3], [4, 5, 6]) plt.title(‘示例图表’, fon…...
mac部署CAT监控服务
在 Mac 上部署美团点评开源的 CAT 监控服务端,可以按照以下步骤操作: 1. 环境准备 1.1 安装依赖 确保已安装以下工具: JDK 8(建议 OpenJDK 11) MySQL 5.7(存储监控数据)(8.0不支持…...
实变函数:集合与子集合一例(20250329)
题目 设 r , s , t r, s, t r,s,t 是三个互不相同的数,且 A { r , s , t } A \{r, s, t\} A{r,s,t}, B { r 2 , s 2 , t 2 } B \{r^2, s^2, t^2\} B{r2,s2,t2}, C { r s , s t , r t } C \{rs, st, rt\} C{rs,st,rt} 若 A B C A B C ABC 则 { r , s…...
软件工程之需求工程(需求获取、分析、验证)
一、需求获取(Requirements Elicitation) 1. 定义与目标 需求获取是通过与用户、利益相关者等交互,识别并捕获系统需求的过程,目标是明确用户意图与业务目标,避免后期因需求偏差导致返工。 2. 主要方法 问卷法&…...
c++第三课(基础c)
1.前文 2.break 3.continue 4.return 0 1.前文 上次写文章到现在,有足足这么多天(我也不知道,自己去数吧) 开始吧 2.break break是结束循环的意思 举个栗子 #include<bits/stdc.h> using namespace std; int main(…...
基于Elasticsearch的个性化内容推荐技术实践
近期开发了一款新的app,并深度参与的全流程的构建及开发,在开发首页内容推荐的时候,写了一套通过ES实现的推荐算法,小有所得,写此博客记录一下。 一、Elasticsearch在推荐系统中的核心作用 1.1 实时索引与检索 Elast…...
el-radio-group 中 el-radio-button value未能绑定上数值数据
这样绑定到admin后不会随着admin的值显示 在value加上 : 后成功显示...
Python Cookbook-4.13 获取字典的一个子集
任务 你有一个巨大的字典,字典中的一些键属于一个特定的集合,而你想创建一个包含这个键集合及其对应值的新字典。 解决方案 如果你不想改动原字典: def sub_dict(somedict,somekeys,default None):return dict([(k, somedict.get(k,default)) for k…...
JSP(实验):带验证码的用户登录
[实验目的] 1.掌握应用request对象获取表单提交的数据。 2.掌握解决获取表单提交数据产生中文乱码的问题。 3.掌握使用response对象进行定时跳转功能。 4.掌握使用session对象完成登录和注销功能。 [实验要求] 设计带验证码…...
自然语言模型的演变与未来趋势:从规则到多模态智能的跨越
自然语言模型的演变与未来趋势:从规则到多模态智能的跨越 自然语言处理(NLP)作为人工智能领域最具挑战性的分支之一,在过去几十年经历了翻天覆地的变化。从最初基于规则的系统到如今拥有万亿参数的大型语言模型(LLMs),这一技术革新不仅彻底改…...
集多功能为一体的软件,支持批量操作。
今天我给大家分享一个超实用的小工具,真的是太好用了!这个软件是吾爱大神无知灰灰制作的,它能直接一键把webp格式的图片转换成png格式。 webp转为png 一键操作,支持压缩 其实,作者最近在工作中经常遇到webp格式的图片…...
linux压缩指令
今天我们来了解一下linux压缩指令,压缩是我们文件传输的一种重要手段,对此,我们是必须学习压缩指令的,那么话不多说,来看. 1.grep过滤查找,管道符,“|”,表示将前一个命令的处理结果输出传递给后面的命令处理。 基本语法&#x…...
C++细节知识for面试
1. linux上C程序可用的栈和堆大小分别是多少,为什么栈大小小于堆? 1. 栈(Stack)大小 栈默认为8MB,可修改。 为什么是这个大小: 安全性:限制栈大小可防止无限递归或过深的函数调用导致内存…...
Appium中元素定位的注意点
应用场景 了解这些注意点可以以后在出错误的时候,更快速的定位问题原因。 示例 使用 find_element_by_xx 或 find_elements_by_xx 的方法,分别传入一个没有的“特征“会是什么结果呢? 核心代码 driver.find_element_by_id("xxx") drive…...
污水处理厂人员定位方案-UWB免布线高精度定位
1. 方案概述 本方案采用免布线UWB基站与北斗卫星定位融合技术,结合UWBGNSS双模定位工卡,实现污水处理厂室内外人员高精度定位(亚米级)。系统通过低功耗4G传输数据,支持实时位置监控、电子围栏、聚集预警、轨迹回放等功…...
蓝桥刷题note11(好数)
1,好数 一个整数如果按从低位到高位的顺序,奇数位 (个位、百位、万位 ⋯⋯ ) 上的数字是奇数,偶数位 (十位、千位、十万位 ⋯⋯ ) 上的数字是偶数,我们就称之为 “好数”。 给定一个正整数 NN,请计算从 1 到 NN 一共…...
Elasticsearch 高级
Elasticsearch 高级 建议阅读顺序: Elasticsearch 入门Elasticsearch 搜索Elasticsearch 搜索高级Elasticsearch高级(本文) 1. nested 类型 1.1 介绍 Elasticsearch 中的 nested 类型允许你在文档内存储复杂的数据结构,比如一个…...
SQL Server 2022常见问题解答
以下是SQL Server 2022的常见问题解答,按主题分类整理: 一、安装与升级 SQL Server 2022的系统要求是什么? 支持的操作系统:Windows Server 2016及以上、Linux(Ubuntu 20.04/22.04, RHEL 8/9等)。内存:至少4GB(建议8GB+)。磁盘空间:6GB以上,具体取决于安装组件。如何…...
基于LLM的实时信息检索汇总分析系统
基于用户需求和技术发展趋势,设计基于LLM的实时信息检索汇总分析系统,方案如下: 一、系统架构设计 1. 分层多模态数据采集层 动态渲染适配引擎 采用混合爬虫技术: 静态页面:优化Scrapy框架,集成XPath模板库…...
C语言笔记数据结构(链表)
希望文章能对你有所帮助,有不足的地方请在评论区留言指正,一起交流学习! 目录 1.链表 1.1 链表概念和组成 1.2 链表的分类 1.3 顺序表和链表 2.单链表(无头单向不循环链表) 2.1 结点的创建 2.2 创建新的结点 2.3 单链表的打印 2.4 尾…...
Leetcode 两数相除
✅ LeetCode 29. 两数相除 — 思路总览 🧩 题目要求 给定两个整数 dividend 和 divisor,实现 整数除法,不能使用乘法 *、除法 / 和取余 % 运算符。 要求返回的结果应为 向零截断的整数商,即: 正数向下取整…...
C++ 初阶总复习 (16~30)
C 初阶总复习 (16~30) 目的16. 2009. volatile关键字的作用17. 2010.什么是多态 简单介绍下C的多态18. 2011. 什么是虚函数 介绍下C中虚函数的原理19. 2012 构造函数可以是虚函数嘛20. 2013.析构函数一定要是虚函数嘛?21. 2015. 什么是C中的虚…...
Koordinator-Metric查询
以CollectAllPodMetricsLast()举例,看看koordinator怎样使用tsdb进行查询。 CollectAllPodMetricsLast() GenerateQueryParamsLast()传入metric采集间隔2倍时间调用CollectAllPodMetrics()func CollectAllPodMetricsLast(statesInformer statesinformer.StatesInformer, metr…...
人工智能图像识别Scala介绍
Scala 一.Scala 简介 Scala即Scalable Language(可伸缩的语言),Scala 语言是由 Martin Odersky 等人在 2003 年开发的,并于 2004 年首次发布。意味着这种语言设计上支持大规模软件开发,是一门多范式的编程语言。 Sc…...
