javaEE初阶——多线程(九)——JUC常见的类以及线程安全的集合类

news2024/12/23 15:30:48

在这里插入图片描述

T04BF

👋专栏: 算法|JAVA|MySQL|C语言

🫵 小比特 大梦想

此篇文章与大家分享多线程专题的最后一篇文章:关于JUC常见的类以及线程安全的集合类
如果有不足的或者错误的请您指出!

目录

    • 3.JUC(java.util.concurrent)常见的类
      • 3.1Callable接口
      • 3.2 RentrantLock
        • ReentrantLock提供了公平锁的实现
        • ReentrantLock提供了tryLock
        • Condition
      • 3.3 Semaphore
      • 3.4CountDownLatch
    • 4.线程安全的集合类
      • 4.1多线程环境下使用ArrayList
        • 4.1.1Collection.synchronizedList(new ArrayList)
        • 4.1.2CopyOnWriteArrayList
      • 4.2多线程使用队列
      • 4.3多线程使用哈希表

3.JUC(java.util.concurrent)常见的类

3.1Callable接口

Callable和Runnable一样,都是用来描述一个任务的
但是区别在于 ,用Callable描述的任务是有返回值的,而通过Runnable描述的任务是没有返回值的(即run方法的返回值是void)
通过Runnable,要想获取到"返回值",只能通过一些特定的手段
在这里插入图片描述
但是这个方法,主线程和 t线程的耦合太大了
而Callable就是为了会更优雅的解决上面的问题
在这里插入图片描述
但是Thread并没有提供这样的构造方法
我们可以将callable传入FutureTask
在这里插入图片描述

3.2 RentrantLock

表示可重入的锁
相对于我们常用的Synchronized,ReentrantLock是"手动"进行加锁和解锁的

    public static void main(String[] args) {
        ReentrantLock lock = new ReentrantLock();
        //加锁
        lock.lock();
        //解锁
        lock.unlock();
    }

但是这种就容易"漏掉"解锁操作,就会出现大问题,因此我们经常搭配finally使用
在这里插入图片描述
既然这个这么麻烦,那还有存在的价值嘛??
实际上价值还是很大的

ReentrantLock提供了公平锁的实现

在这里插入图片描述
如果传入true就是表示公平锁,传入false / 不传 就是非公平锁

ReentrantLock提供了tryLock

所谓tryLock就是尝试加锁
如果在遇到锁已经被占有了,那就直接返回
而相比于synchronized则是阻塞等待
另外,除了直接返回外,tryLock还提供了带等待超时的版本

Condition

Synchronized是搭配 wait 和 notify使用
而ReentrantLock是搭配Condition使用
实际上Condition比wait和notify更加智能,因为它可以指定唤醒那个线程

3.3 Semaphore

表示信号量,用来表示"可用资源"的个数,本质上就是个计数器
围绕信号量主要有两个基本操作
(1)P操作,即申请资源,计数器 -1;
(2)V操作,即释放资源,计数器+1;
在这里插入图片描述
但我们申请的资源超过信号量本身的大小们,就会阻塞等待,直到其他地方释放资源
在这里插入图片描述
那么当资源数目为1的话,就可以当成锁来使用了
在这里插入图片描述

因为如果信号量有0 1两个取值,此时就是"二元信号量",本质上就是一把锁

3.4CountDownLatch

表示同时等待多个线程结束
是一个比较实用的工具
当我们把一个任务拆解成多个线程来完成时,就可以利用这个工具类来判断,任务整体是否完成了
在这里插入图片描述
此时的执行结果就是:
在这里插入图片描述
await会阻塞等待,一直到countDown调用的次数,和构造方法指定的次数一致的时候,await才会返回

而await不仅仅能够替代join,假设现在有1000个任务要交给4个线程来使用,那么如何判断1000个任务已经执行结束??就可以使用countDownLatch来判断

4.线程安全的集合类

原来的集合类.比如ArrayList,LinkedList,HashMap等等,都是线程不安全的
而Vector自带了synchronized,Stack继承了ector,HashTable也是自带的synchronized,在一定程度上是线程安全的

但是不能说太绝对,还是要具体情况具体分析 就比如可能出现下面这种情况:
在这里插入图片描述
就比如上述代码,线程1执行到if条件判断后,线程2把vector给清空了,就会出现bug

如果需要用到其他的类,就需要手动加锁,来保证线程安全,但不同情况下加锁的情况是不一样的,手动加锁是比较麻烦的

标准库就提供了一些具体的解决方法

4.1多线程环境下使用ArrayList

4.1.1Collection.synchronizedList(new ArrayList)

这种方法就相当于给这些集合类套了一层壳,壳上对集合类里面的一些关键方法加上了锁,起到了类似Vector的效果

4.1.2CopyOnWriteArrayList

利用的是"写时拷贝"的思想
假设我们现在有一组数据为1 2 3 4,此时某个线程对数据进行了修改,就把2 修改成200,3修改成300,但是在修改的时候有别到线程在读,如果直接修改就有可能出现2,300这样的中间数据
而写时拷贝就是将原来的数据集拷贝一份,这样修改的时候是在新拷贝的数据集上修改的,而读的时候是在旧的数据集上读的
等到修改完后,就用新的数据集的引用代替原来旧的数据集的引用
这样的过程中,不会出现任何加锁和阻塞等待,也保证读数据不会出现"错误的数据"

这种操作实际上实用性非常高,就比如有的服务器需要更新配置文件 / 数据文件,就可以采取上述策略

4.2多线程使用队列

直接使用BlockingQueue即可

4.3多线程使用哈希表

HashMap是线程不安全的,而HashTable是带锁的
但是实际上HashTable并不推荐使用
因为HashTable本质上就是简单粗暴将每一个方法都进行加锁,就相当于针对了this加锁,此时只要针对HashTable上的元素进行操作,就都会涉及到锁
推荐使用的是 ConcurrentHashTable
它的优点就在于:
(1)采用锁桶的方式,来代替之前的"全局一把锁"
在这里插入图片描述
此时如果两个线程针对的是不同链表上的元素进行操作,是不会涉及到锁冲突的
而本身,操作两个链表上的元素,不涉及公共变量,是不会有线程安全问题的
进行这样的操作实际上收益是很多的
因为在一个Hash表里面,桶的数量是很多的,此时按照我们上面的操作进行加锁,大部分情况是可以避免锁冲突的

那么好像锁多了,锁对象就多了是不是更加麻烦了??
实际上,由于java中任何的对象都可以作为锁对象,我们只需将每一个链表的头结点作为锁对象即可

(2)引入CAS机制
实际上即使是上面的操作,也不能保证线程安全
像哈希表的size,即使你插入的是不同链表的元素,修改的时候也会涉及到多线程修改同一个变量
此时引入了CAS机制,通过CAS来修改size,也就不涉及加锁操作了

(3)针对扩容进行了特殊优化

在哈希表中,如果发现负载因子太大了,就需要扩容,而扩容是一比较低效的操作,普通的hash表如果要在一次put完成整个扩容操作,就会使得put非常卡,如果平时使用put假设是1ms,但某次put执行了1000ms,就会造成不好的体验

ConcurrentHashMap进行的实际上是"化整为零",在扩容的时候会搞两份空间

一份是扩容前的空间,一份是扩容后的空间

接下载每次进行哈希表的基本操作的时候,都会将一部分数据从旧空间搬到新空间

不是一口气搬完,分多次搬

搬的过程中,

如果进行的是插入操作,那就插到新的空间里面

如果是删除,那么旧的新的都会删除

如果是查找,那么旧的新的都要查找一遍

就是"重哈希"过程,重哈希过程结束的标志通常是所有元素都被成功地移动到了新的空间中,并且旧空间中不再包含任何元素。

感谢您的访问!!期待您的关注!!!

在这里插入图片描述

T04BF

🫵 小比特 大梦想

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

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

相关文章

Yolov5 v7.0目标检测——详细记录环境配置、自定义数据处理、模型训练与常用错误解决方法(数据集为河道漂浮物)

1. Yolov5 YOLOv5是是YOLO系列的一个延伸,其网络结构共分为:input、backbone、neck和head四个模块,yolov5对yolov4网络的四个部分都进行了修改,并取得了较大的提升,在input端使用了Mosaic数据增强、自适应锚框计算、自…

鸿蒙云函数调试坑点

如果你要本地调试请使用 const {payload, action} event.body/** 本地调试不需要序列化远程需要序列化 */ // const {payload, action} JSON.parse(event.body) const {payload, action} event.body 注意: 只要修改云函数,必须上传云函数 如果使用 const {pay…

牛客NC98 判断t1树中是否有与t2树完全相同的子树【simple 深度优先dfs C++/Java/Go/PHP】

题目 题目链接: https://www.nowcoder.com/practice/4eaccec5ee8f4fe8a4309463b807a542 思路 深度优先搜索暴力匹配 思路和算法这是一种最朴素的方法——深度优先搜索枚举 s 中的每一个节点,判断这个点的子树是否和 t 相等。如何判断一个节点的子树是否…

HTTP/1.1,HTTP/2.0和HTTP/3.0 各版本协议的详解(2024-04-24)

1、HTTP介绍 HTTP 协议有多个版本,目前广泛使用的是 HTTP/1.1 和 HTTP/2,以及正在逐步推广的 HTTP/3。 HTTP/1.1:支持持久连接,允许多个请求/响应通过同一个 TCP 连接传输,减少了建立和关闭连接的消耗。 HTTP/2&#…

基于STM32和阿里云的智能台灯(STM32+ESP8266+MQTT+阿里云+语音模块)

一、主要完成功能 1、冷光模式和暖光模式两种灯光 主要支持冷光和暖光模式两种,可以通过语音模块或手机app远程切换冷暖光 2、自动模式和手动模式 主要支持手动模式和自动两种模式(app或语音助手切换) (1)自动模式:根据环境光照…

vscode 使用文件模板功能来添加版权信息

vscode 新建文件的时候,自动填充作者及版权信息 无需使用插件,操作如下: 选择 “首选项(Preferences)”。在搜索框中输入 “file template” 或者 “文件模板”,然后选择相关的设置项。 {"C_Cpp.clang_format_fallbackSt…

[lesson58]类模板的概念和意义

类模板的概念和意义 类模板 一些类主要用于存储和组织数据元素 类中数据组织的方式和数据元素的具体类型无关 如:数组类、链表类、Stack类、Queue类等 C中将模板的思想应用于类,使得类的实现不关注数据元素的具体类型,而只关注类所需要实现的功能。 C中的类模板…

Docker 开启远程安全访问

说明 如果你的服务器是公网IP,并且开放了docker的远程访问,如果没有进行保护是非常危险的,任何人都可以向你的docker中推送镜像、运行实例。我曾开放过阿里云服务器中docker的远程访问权限,在没有开启保护的状态下,几…

企业微信hook接口协议,根据手机号搜索联系人

根据手机号搜索联系人 参数名必选类型说明uuid是String每个实例的唯一标识,根据uuid操作具体企业微信 请求示例 {"uuid":"3240fde0-45e2-48c0-90e8-cb098d0ebe43","phoneNumber":"1357xxxx" } 返回示例 {"data&q…

抖音 小程序 获取手机号 报错 getPhoneNumber:fail auth deny

这是因为 当前小程序没有获取 手机号的 权限 此能力仅支持小程序通过试运营期后可用,默认获取权限,无需申请; https://developer.open-douyin.com/docs/resource/zh-CN/mini-app/develop/guide/open-capabilities/acquire-phone-number-acqu…

用斐波那契数列感受算法的神奇(21亿耗时0.2毫秒)

目录 一、回顾斐波那契数列 二、简单递归方法 (一)解决思路 (二)代码展示 (三)性能分析 三、采用递归HashMap缓存 (一)解决思路 (二)代码展示 &…

深度学习系列65:数字人openHeygen详解

1. 主流程分析 从inference.py函数进入,主要流程包括: 1) 使用cv2获取视频中所有帧的列表,如下: 2)定义Croper。核心代码为69行:full_frames_RGB, crop, quad croper.crop(full_frames_RGB)。…

公开课学习——基于索引B+树精准建立高性能索引

文章目录 遇到慢查询怎么办?—— 创建索引联合索引的底层的数据存储结构长什么样? mysql脑图 阿里开发手册 遇到慢查询怎么办?—— 创建索引 不用索引的话一个一个找太慢了,用索引就快的多。 假如使用树这样的结构建立索引&#x…

Spring - 3 ( 12000 字 Spring 入门级教程 )

一:Spring Web MVC入门 1.1 响应 在我们前⾯的代码例子中,都已经设置了响应数据, Http 响应结果可以是数据, 也可以是静态页面,也可以针对响应设置状态码, Header 信息等. 1.2 返回静态页面 创建前端页面 index.html(注意路径) html代码 …

frp 实现 http / tcp 内网穿透(穿透 wordpress )

frp 实现 http / tcp 内网穿透(穿透 wordpress ) 1. 背景简介与软件安装2. 服务端配置2.1 配置文件2.2 wordpress 配置文件2.3 frps 自启动 3.客户端配置3.1 配置文件3.2 frpc 自启动 同步发布在个人笔记frp 实现 http / tcp 内网穿透(穿透 w…

HZNUCTF -- web

HZNUCTF第五届校赛实践赛初赛 Web方向 WriteUp-CSDN博客 ezssti 下载文件 访问 /login 可由源代码中看到 Eval 函数 ,可以任意命令执行 按照格式,可执行命令 POST :name{{.Eval "env"}} 可以得到flag (尝试ls 只能列出…

就业班 第三阶段(负载均衡) 2401--4.19 day3

二、企业 keepalived 高可用项目实战 1、Keepalived VRRP 介绍 keepalived是什么keepalived是集群管理中保证集群高可用的一个服务软件,用来防止单点故障。 ​ keepalived工作原理keepalived是以VRRP协议为实现基础的,VRRP全称Virtual Router Redundan…

微软发布Phi-3 Mini,性能媲美GPT-3.5、Llama-3,可在手机端运行

前言 微软发布了最新版的Phi系列小型语言模型(SLM) - Phi-3。这个系列包括3个不同参数规模的版本:Phi-3 Mini (38亿参数)、Phi-3 Small (70亿参数)和Phi-3 Medium (140亿参数)。 Phi系列模型是微软研究团队开发的小规模参数语言模型。从第一代Phi-1到第二代Phi-2&…

kubebuilder(3)实现operator

在前面的文章我们已经了解了operator项目的基本结构。现在我们来写一点简单的代码,然后把我们的crd和operator部署到k8s集群中。 需求 这是一个真实的需求,只不过做了简化。 在开发公司自己的paas平台,有一个需求是,用户在发版…

【Linux高性能服务器编程】两种高性能并发模式剖析——领导者/追随者模式

hello !大家好呀! 欢迎大家来到我的Linux高性能服务器编程系列之两种高性能并发模式介绍,在这篇文章中,你将会学习到高效的创建自己的高性能服务器,并且我会给出源码进行剖析,以及手绘UML图来帮助大家来理解…