当前位置: 首页 > news >正文

javaEE-多线程进阶-JUC的常见类

juc:指的是java.util.concurrent包,该包中加载了一些有关的多线程有关的类。

目录

一、Callable接口

FutureTask类

参考代码:

二、ReentrantLock 可重入锁

ReentrantLock和synchronized的区别:

1.ReentantLock还有一个方法:tryLock:尝试上锁。

2.ReentantLock可以实现公平锁

3,ReentrantLock和synchronized的等待通知机制不同

三、semaphore 信号量

四、CountDownLatch 同时等待多个任务执行结束

五、实现线程安全的方式总结

六、创建线程的方式总结

七.线程安全的集合类

1.多线程环境使用集合:ArrayList

1>.用synchronized加锁,保证线程安全.

2>.使用Collectios.synchronizedList(new ArrayList)

3>.使用CopyOnWriteArrayList  写时拷贝

2.多线程环境使⽤队列

1>.自己加锁保证线程安全。

2>.使用阻塞队列BlockingQueue(线程安全的).

3.多线程环境使用哈希表

1>.HashTable

2>.ConcurrentHashMap:并发哈希表



一、Callable接口

Callable是一个接口,将线程封装在方法中,带有一个返回值,用于实现计算,并获取结果类型的任务。相当于把线程封装了⼀个"返回值".⽅便借助多线程的⽅式计算结果.它的作用与Runnable类似.

计算1+2+3+...+1000:

按照之前的方法,要先定义一个成员变量,在一个线程中进行累加,并返回累加的结果,还要用join等该线程执行结束,之后才能得到结果:

这种方式感觉不太美观,Callable是一个接口,就是处理这种带有返回值的多线程任务的;

Callable是一个泛型接口,指定的类型就是要返回结果的类型。

通过 匿名内部类 实现该接口的call方法,来完成要实现的任务:

FutureTask类

在Thread类中,并没有提供构造函数来传入Callable。但JVM提供了另一个类,FutureTask类:未来任务,作为Thread类和Callable接口的 “粘合剂”,

FutureTask提供了可以传Callable的构造方法,且Thread提供了可以传FutureTask类的构造方法,这就可以将两者结合起来;FutureTask类也是泛型类,指定的类型就是传入的Callable的返回类型:

对FutureTask类的理解:

Callable完成任务是需要时间的,该任务是在未来完成的,最后取结果的时候 需要一个凭据,FutureTask 就是这个凭据。

通过调用FutureTask的get方法,可以得到Callable的返回值;get方法是带有阻塞的,当传入的Callable没有完成任务,返回数据时,get方法就处于阻塞等待状态。

参考代码:


/***  Callable接口 带有返回值*   通过匿名内部类 ,重写它的 call方法完成任务 *  通过 FutureTask类 将Thread与Callable连接*/public static void main(String[] args) throws ExecutionException, InterruptedException {Callable<Integer> callable = new Callable<Integer>(){@Overridepublic Integer call() throws Exception {int sum=0;for(int i = 1; i <= 1000; i++ ){sum +=i;}return sum;}};
//        Thread thread = new Thread(callable);FutureTask<Integer> futureTask = new FutureTask<>(callable);Thread thread = new Thread(futureTask);thread.start();System.out.println("sum= "+ futureTask.get());}//普通方法:private static int sum=0;//定义一个 静态成员变量public static void main2(String[] args) throws InterruptedException {Thread t=new Thread(()->{for(int i = 1;i <= 1000;i++){sum += i;}});t.start();t.join();//要等t线程执行结束System.out.println("sum= " + sum);}

Callable和Runnable相比,Callable在实现计算,并有返回值的任务时,代码看上去更美观,别的和Runnable功能是一样的。

二、ReentrantLock 可重入锁

可重入锁,和synchronized锁类似。

这个锁提供了两个方法:lock(上锁) unlocker(解锁)

使用这个锁的时候要注意解锁代码的放置位置;上锁后,在代码执行过程中,遇到return 或者异常终止了,就可能引起 unlock没有被执行,锁没有释放。因此,正确使用ReentrantLock锁 是把unlock放在 finall代码块中,这样就能防止 锁未被释放了。

ReentrantLock和synchronized的区别:

1.ReentantLock还有一个方法:tryLock:尝试上锁。

lock:直接加锁,加锁不成功,就进行阻塞;tryLock:尝试上锁,上锁不成功,返回false,不会进入阻塞状态。提供了更多的可操作空间。

创建两个线程t1,t2;对两个线程都用tryLock上锁,t1线程先获取到了锁,并返回true;t2未获取到锁,返回了false,但并未阻塞,而是继续执行代码,打印了"Thread 02",因为未加锁成功,也就无法解锁,t2的unlock就抛出了异常;之后,t1的休眠时间到,打印“Thread 01",解锁。

2.ReentantLock可以实现公平锁

ReentantLock提供的实现公平锁的方法,通过一个队列,按照先来后到的方式,将线程放到队列中,按照队列中的方式执行。

3,ReentrantLock和synchronized的等待通知机制不同

synchronized通过 wait/notify 来实现;

ReentrantLock通过Condition方法来实现,

三、semaphore 信号量

信号量,⽤来表⽰"可⽤资源的个数".本质上就是⼀个计数器.

就类似停车场:用N记录当前可停车位,

有车进来停车,N-1;有车开走,N+1。这个N就表示可用资源的个数。

设“可⽤资源的个数"用 N来表示:

申请一个资源,会使N-1,称为“P操作”;释放一个资源,会使N+1,称为“V操作”。如果N为0了,继续P操作,则会进行阻塞

信号量是操作系统内部提供的一种机制,操作系统对应的api被JVM封装下,就能通过java代码来调用其相关的操作了。

在java中,用 acquire方法,表示申请;release方法,表示释放

锁就是一种特殊的信号量,可以认为是计数值为1的信号量:释放锁状态,就是1;加锁状态,就是0。对于这种非0即1的信号量,称为二元信号量

Semaphore( n ):传参数的构造方法,参数表示可用资源的个数. 当n=1时(也就相当于一个锁了),通过acquire申请资源,打印“信号量1”,再申请资源,就会进入阻塞状态。

四、CountDownLatch 同时等待多个任务执行结束

CountDownLatch是多线程在特定场景中使用的一个小工具:功能与join类似,join是等待一个进程结束;CountDownLatch 可同时等待 N个任务执行结束。

 代码案例:同时等待10个线程结束, 创建10个线程,同时执行下载任务,main线程 等待结束.

 /*** CountDownLatch:可同时等待多个线程结束* 设同时等待10个线程结束* 创建10个线程,同时下载,等待结束*/
public static void main(String[] args) throws InterruptedException {CountDownLatch countDownLatch = new CountDownLatch(10);//10表示:同时等待10个线程结束for(int i=0;i<10;i++){ //创建10个线程 负责下载int n=i;new Thread(()->{System.out.println("开始下载: "+n);Random random = new Random();long s=(random.nextInt(5)+1)*1000;try {Thread.sleep(s);//每个线程设置随机休眠时间} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println("结束下载: "+n);countDownLatch.countDown();//执行完一个线程,就记录一下}).start();}countDownLatch.await();System.out.println("main ");}

执行结果:

五、实现线程安全的方式总结

1.synchronized锁

2.ReentrantLock可重入锁

3.CAS原子类

4.Semaphore信号量

六、创建线程的方式总结

1.通过继承Thread类及其匿名内部类方式

2.通过实现Runnable接口及匿名内部类方式

3.基于lambda方式

4.基于线程池

5.通过实现Callable接口方式创建

七.线程安全的集合类

Vector,Stack,HashTable,是线程安全的(不建议⽤),其他的集合类不是线程安全的.

1.多线程环境使用集合:ArrayList

保证在多线程安全下的使用方式:

1>.用synchronized加锁,保证线程安全.

2>.使用Collectios.synchronizedList(new ArrayList)

通过Collections类,关键位置都加上synchronized锁,保证线程安全. synchronizedList是标准库提供的⼀个基于synchronized进⾏线程同步的List.synchronizedList 的关键操作上都带有synchronized

相当于给ArrayList加了个壳,加壳后新的集合 list 就是线程安全的了.

3>.使用CopyOnWriteArrayList  写时拷贝

CopyOnWrite容器即写时复制的容器。

当多个线程只进行读操作的时候,不会产生线程安全问题;当要对数组修改时,会先将顺序表复制一benneg份,修改新的表中的内容,再将引用指向新的数组.(这里的操作是原子的,不用加锁)

使用CopyOnWriteArrayList 的利弊:

优点:在多读少写的情况下,无需加锁就解决了ArrayList的线程安全问题,提高了性能。

缺点:对数组的修改不能太频繁;数组不能太长,这些可能会导致复制操作成本太高。

2.多线程环境使⽤队列

1>.自己加锁保证线程安全。

2>.使用阻塞队列BlockingQueue(线程安全的).

3.多线程环境使用哈希表

HashMap是线程不安全的,HashTable是线程安全的duoxianceh

多线程环境使用哈希表可以使用:

1>.HashTable

2>.ConcurrentHashMap:并发哈希表

HashTable是把关键方法上都加了synchronized锁,也就是一个线程对数组中某条链表操作时,别的线程都不能对该数组操作,HashTable在多线程下的执行效率是很慢的。

ConcurrentHashMap: 对HashTable进行了改进和优化

1>.优化了加锁方式

对读操作没有加锁,(只是使用Volatile修饰,确保从内存读数据,读到的是刚修改过的数据)只对写操作进行加锁,且缩小了锁的粒度,不再将整个数组都加锁,对每个链表都分配了一把锁(将每个链表的头节点对象设为锁),只有当多个线程访问同一个链表时,才会产生锁冲突。这样就降低了锁冲突,提高了效率。

2>.充分利用CAS原子操作特性

⽐如size属性通过CAS来更新.避免出现重量级锁的情况.

3>.优化了扩容方式

HashTable通过计算负载因子,判断是否需要扩容,达到要扩容的值,就直接扩容:创建新数组,将原来的数据全复制到新数组中。当数据量非常的时,扩容操作会进行的比较慢,表现出来的就是在运行的某一时刻比较慢,不具有稳定性。

ConcurrentHashMap对此进行了优化,通过“化整为零”方式进行扩容,不是一下将全部数据进行拷贝,而是进行分批拷贝

当需要扩容时,先创建一个新的数组,每次将一部分数据拷贝到新数组中,后续每个来操作ConcurrentHashMap的线程,都会参与搬家的过程.每个操作负责搬运⼀⼩部 分元素.这个过程中新老哈希表都存在,扩容结束,删除旧表;

扩容期间,进行插入操作:直接向新数组中进行插入;

                删除操作:对新老数组都进行删除操作;

                查找操作:对新老数组都进行查找操作;

相关文章:

javaEE-多线程进阶-JUC的常见类

juc:指的是java.util.concurrent包&#xff0c;该包中加载了一些有关的多线程有关的类。 目录 一、Callable接口 FutureTask类 参考代码&#xff1a; 二、ReentrantLock 可重入锁 ReentrantLock和synchronized的区别&#xff1a; 1.ReentantLock还有一个方法&#xff1a…...

Flume拦截器的实现

Flume conf文件编写 vim file_to_kafka.conf#定义组件 a1.sources r1 a1.channels c1#配置source a1.sources.r1.type TAILDIR a1.sources.r1.filegroups f1 a1.sources.r1.filegroups.f1 /Users/zhangjin/model/project/realtime-flink/applog/log/app.* # 设置断点续传…...

Swift Combine 学习(四):操作符 Operator

Swift Combine 学习&#xff08;一&#xff09;&#xff1a;Combine 初印象Swift Combine 学习&#xff08;二&#xff09;&#xff1a;发布者 PublisherSwift Combine 学习&#xff08;三&#xff09;&#xff1a;Subscription和 SubscriberSwift Combine 学习&#xff08;四&…...

leetcode 173.二叉搜索树迭代器栈绝妙思路

以上算法题中一个比较好的实现思路就是利用栈来进行实现&#xff0c;以下方法三就是利用栈来进行实现的&#xff0c;思路很好&#xff0c;很简练。进行next的时候&#xff0c;先是一直拿到左边的子树&#xff0c;直到null为止&#xff0c;这一步比较好思考一点&#xff0c;下一…...

df.groupby([pd.Grouper(freq=‘1M‘, key=‘Date‘), ‘Buyer‘]).sum()

df.groupby([pd.Grouper(freq1M, keyDate), Buyer]).sum() 用于根据特定的时间频率和买家&#xff08;Buyer&#xff09;对 DataFrame 进行分组&#xff0c;然后计算每个分组的总和。下面是对这行代码的逐步解释&#xff1a; df.groupby([...])&#xff1a;这个操作会根据传入的…...

LLM - 使用 LLaMA-Factory 部署大模型 HTTP 多模态服务 (4)

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://spike.blog.csdn.net/article/details/144881432 大模型的 HTTP 服务&#xff0c;通过网络接口&#xff0c;提供 AI 模型功能的服务&#xff0c;允许通过发送 HTTP 请求&#xff0c;交互…...

icp备案网站个人备案与企业备案的区别

个人备案和企业备案是在进行ICP备案时需要考虑的两种不同情况。个人备案是指个人拥有的网站进行备案&#xff0c;而企业备案则是指企业或组织名下的网站进行备案。这两者在备案过程中有一些明显的区别。 首先&#xff0c;个人备案相对来说流程较为简单。个人备案只需要提供个人…...

如何不修改模型参数来强化大语言模型 (LLM) 能力?

前言 如果你对这篇文章感兴趣&#xff0c;可以点击「【访客必读 - 指引页】一文囊括主页内所有高质量博客」&#xff0c;查看完整博客分类与对应链接。 大语言模型 (Large Language Model, LLM, e.g. ChatGPT) 的参数量少则几十亿&#xff0c;多则上千亿&#xff0c;对其的训…...

AF3 AtomAttentionEncoder类的init_pair_repr方法解读

AlphaFold3 的 AtomAttentionEncoder 类中,init_pair_repr 方法方法负责为原子之间的关系计算成对表示(pair representation),这是原子转变器(atom transformer)模型的关键组成部分,直接影响对蛋白质/分子相互作用的建模。 init_pair_repr源代码: def init_pair_repr(…...

DDoS攻击防御方案大全

1. 引言 随着互联网的迅猛发展&#xff0c;DDoS&#xff08;分布式拒绝服务&#xff09;攻击成为了网络安全领域中最常见且危害严重的攻击方式之一。DDoS攻击通过向目标网络或服务发送大量流量&#xff0c;导致服务器过载&#xff0c;最终使其无法响应合法用户的请求。本文将深…...

Vue中常用指令

一、内容渲染指令 1.v-text&#xff1a;操作纯文本&#xff0c;用于更新标签包含的文本&#xff0c;但是使用不灵活&#xff0c;无法拼接字符串&#xff0c;会覆盖文本&#xff0c;可以简写为{{}}&#xff0c;{{}}支持逻辑运算。 用法示例&#xff1a; //把name对应的值渲染到…...

Servlet解析

概念 Servlet是运行在服务端的小程序&#xff08;Server Applet)&#xff0c;可以处理客户端的请求并返回响应&#xff0c;主要用于构建动态的Web应用&#xff0c;是SpringMVC的基础。 生命周期 加载和初始化 默认在客户端第一次请求加载到容器中&#xff0c;通过反射实例化…...

带虚继承的类对象模型

文章目录 1、代码2、 单个虚继承3、vbptr是什么4、虚继承的多继承 1、代码 #include<iostream> using namespace std;class Base { public:int ma; };class Derive1 :virtual public Base { public:int mb; };class Derive2 :public Base { public:int mc; };class Deri…...

深度学习中的离群值

文章目录 深度学习中有离群值吗&#xff1f;深度学习中的离群值来源&#xff1a;处理离群值的策略&#xff1a;1. 数据预处理阶段&#xff1a;2. 数据增强和鲁棒模型&#xff1a;3. 模型训练阶段&#xff1a;4. 异常检测集成模型&#xff1a; 如何处理对抗样本&#xff1f;总结…...

如何利用Logo设计免费生成器创建专业级Logo

在当今的商业世界中&#xff0c;一个好的Logo是品牌身份的象征&#xff0c;它承载着公司的形象与理念。设计一个专业级的Logo不再需要花费大量的金钱和时间&#xff0c;尤其是当我们拥有Logo设计免费生成器这样的工具时。接下来&#xff0c;让我们深入探讨如何利用这些工具来创…...

Mysql SQL 超实用的7个日期算术运算实例(10k)

文章目录 前言1. 加上或减去若干天、若干月或若干年基本语法使用场景注意事项运用实例分析说明2. 确定两个日期相差多少天基本语法使用场景注意事项运用实例分析说明3. 确定两个日期之间有多少个工作日基本语法使用场景注意事项运用实例分析说明4. 确定两个日期相隔多少个月或多…...

运算指令(PLC)

加 ADD 减 SUB 乘 MUL 除 DIV 浮点运算 整数运算...

「Mac畅玩鸿蒙与硬件49」UI互动应用篇26 - 数字填色游戏

本篇教程将带你实现一个数字填色小游戏&#xff0c;通过简单的交互逻辑&#xff0c;学习如何使用鸿蒙开发组件创建趣味性强的应用。 关键词 UI互动应用数字填色动态交互逻辑判断游戏开发 一、功能说明 数字填色小游戏包含以下功能&#xff1a; 数字选择&#xff1a;用户点击…...

机器学习经典算法——逻辑回归

目录 算法介绍 算法概念 算法的优缺点 LogisticRegression()函数理解 环境准备 算法练习 算法介绍 算法概念 逻辑回归&#xff08;Logistic Regression&#xff09;是一种广泛应用于分类问题的机器学习算法。 它基于线性回归的思想&#xff0c;但通过引入一个逻辑函数&…...

【数据仓库金典面试题】—— 包含详细解答

大家好&#xff0c;我是摇光~&#xff0c;用大白话讲解所有你难懂的知识点 该篇面试题主要针对面试涉及到数据仓库的数据岗位。 以下都是经典的关于数据仓库的问题&#xff0c;希望对大家面试有用~ 1、什么是数据仓库&#xff1f;它与传统数据库有何区别&#xff1f; 数据仓库…...

手游刚开服就被攻击怎么办?如何防御DDoS?

开服初期是手游最脆弱的阶段&#xff0c;极易成为DDoS攻击的目标。一旦遭遇攻击&#xff0c;可能导致服务器瘫痪、玩家流失&#xff0c;甚至造成巨大经济损失。本文为开发者提供一套简洁有效的应急与防御方案&#xff0c;帮助快速应对并构建长期防护体系。 一、遭遇攻击的紧急应…...

ES6从入门到精通:前言

ES6简介 ES6&#xff08;ECMAScript 2015&#xff09;是JavaScript语言的重大更新&#xff0c;引入了许多新特性&#xff0c;包括语法糖、新数据类型、模块化支持等&#xff0c;显著提升了开发效率和代码可维护性。 核心知识点概览 变量声明 let 和 const 取代 var&#xf…...

python打卡day49

知识点回顾&#xff1a; 通道注意力模块复习空间注意力模块CBAM的定义 作业&#xff1a;尝试对今天的模型检查参数数目&#xff0c;并用tensorboard查看训练过程 import torch import torch.nn as nn# 定义通道注意力 class ChannelAttention(nn.Module):def __init__(self,…...

rknn优化教程(二)

文章目录 1. 前述2. 三方库的封装2.1 xrepo中的库2.2 xrepo之外的库2.2.1 opencv2.2.2 rknnrt2.2.3 spdlog 3. rknn_engine库 1. 前述 OK&#xff0c;开始写第二篇的内容了。这篇博客主要能写一下&#xff1a; 如何给一些三方库按照xmake方式进行封装&#xff0c;供调用如何按…...

大型活动交通拥堵治理的视觉算法应用

大型活动下智慧交通的视觉分析应用 一、背景与挑战 大型活动&#xff08;如演唱会、马拉松赛事、高考中考等&#xff09;期间&#xff0c;城市交通面临瞬时人流车流激增、传统摄像头模糊、交通拥堵识别滞后等问题。以演唱会为例&#xff0c;暖城商圈曾因观众集中离场导致周边…...

五年级数学知识边界总结思考-下册

目录 一、背景二、过程1.观察物体小学五年级下册“观察物体”知识点详解&#xff1a;由来、作用与意义**一、知识点核心内容****二、知识点的由来&#xff1a;从生活实践到数学抽象****三、知识的作用&#xff1a;解决实际问题的工具****四、学习的意义&#xff1a;培养核心素养…...

C# 求圆面积的程序(Program to find area of a circle)

给定半径r&#xff0c;求圆的面积。圆的面积应精确到小数点后5位。 例子&#xff1a; 输入&#xff1a;r 5 输出&#xff1a;78.53982 解释&#xff1a;由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982&#xff0c;因为我们只保留小数点后 5 位数字。 输…...

在QWebEngineView上实现鼠标、触摸等事件捕获的解决方案

这个问题我看其他博主也写了&#xff0c;要么要会员、要么写的乱七八糟。这里我整理一下&#xff0c;把问题说清楚并且给出代码&#xff0c;拿去用就行&#xff0c;照着葫芦画瓢。 问题 在继承QWebEngineView后&#xff0c;重写mousePressEvent或event函数无法捕获鼠标按下事…...

Yolov8 目标检测蒸馏学习记录

yolov8系列模型蒸馏基本流程&#xff0c;代码下载&#xff1a;这里本人提交了一个demo:djdll/Yolov8_Distillation: Yolov8轻量化_蒸馏代码实现 在轻量化模型设计中&#xff0c;**知识蒸馏&#xff08;Knowledge Distillation&#xff09;**被广泛应用&#xff0c;作为提升模型…...

MySQL 知识小结(一)

一、my.cnf配置详解 我们知道安装MySQL有两种方式来安装咱们的MySQL数据库&#xff0c;分别是二进制安装编译数据库或者使用三方yum来进行安装,第三方yum的安装相对于二进制压缩包的安装更快捷&#xff0c;但是文件存放起来数据比较冗余&#xff0c;用二进制能够更好管理咱们M…...