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

news/2024/5/7 6:56:00

在这里插入图片描述

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.mrgr.cn/p/62644347

相关文章

文件包含漏洞基础

php 中的文件包含函数: incude : require incude_once require_once 为了减少重复性代码的编写; 任意后缀的文件当中只要存在 php 代码就会被当作 php 执行; 本质:由于包含的文件不可控,导致文件包含…

huggingface模型下载至本地并调用教程

huggingface内有许多预训练模型,可以在线调用模型或者将模型部署至本地,但有时候通过网址调用模型会很慢,有些服务器甚至无法通过网址调用… 那么,正题,如何将huggingface的模型部署至本地呢?其实很简单&am…

重发布的原理及其应用

重发布的作用: 在一个网络中,若运行多种路由协议或者相同协议的不同进程;因为协议之间不能直接沟通计算,进程之间也是独立进行转发和运算的,所以,需要使用重发布来实现路由的共享。 条件 : 1&am…

TimThumb——超好用的 PHP 略缩图裁剪插件

TimThumb 是一个非常简洁方便的、用于裁图的 PHP 程序。只要给它设置一些参数,它就可以生成指定图片的缩略图甚至是直接给指定的网站截图。现在很多 WordPress 主题中,都使用的是 TimThumb 这个 PHP 类库进行缩略图处理。(本博客使用的 Nana 主题中的文章略缩图也是用 TimThu…

Laravel 6 - 第十四章 响应

​ 文章目录 Laravel 6 - 第一章 简介 Laravel 6 - 第二章 项目搭建 Laravel 6 - 第三章 文件夹结构 Laravel 6 - 第四章 生命周期 Laravel 6 - 第五章 控制反转和依赖注入 Laravel 6 - 第六章 服务容器 Laravel 6 - 第七章 服务提供者 Laravel 6 - 第八章 门面 Laravel 6 - …

接口自动化测试框架建设的经验与教训

为什么选择这个话题? 一是发现很多“点工”在转型迷茫期都会问一些自动化测试相关的问题,可以说自动化测试是“点工”升级的必经之路;二是Google一下接口自动化测试,你会发现很多自动化测试框架相关的文章,但是大部分…

同旺科技 USB TO SPI / I2C适配器读写24LC256--页写

所需设备: 1、USB 转 SPI I2C 适配器;内附链接 2、24LC256芯片 适应于同旺科技 USB TO SPI / I2C适配器升级版、专业版; 从00地址开始写入64个字节,然后再将64个字节读回; 页写时序: 读时序&#xff1a…

Docker(二)Docker+ server部署极简前端页面

本篇文章介绍如何使用 Dockerserver 将一个极简前端页面进行部署 1.本地运行一个简单的前端页面&#xff0c;再把它部署到服务器上 index.html <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name&quo…

指令优化:基于大型语言模型的指令算子的进化多目标指令优化

指令优化:基于大型语言模型的指令算子的进化多目标指令优化 摘要 基于指令的语言建模在预训练的语言模型中受到了极大的关注。 提出了一种指令优化方法,将指令生成视为一个进化的多目标优化问题,利用大型语言模型(LLM)来模拟指令运算符,包括变异和交叉。 此外,为这些运算…

探索直播+电商系统中台架构:连接消费者与商品的智能纽带

随着直播电商的崛起&#xff0c;电商行业进入了全新的智能时代。直播形式的互动性和即时性为消费者提供了全新的购物体验&#xff0c;而电商平台则为商品的展示、销售和配送提供了强大的支持。在这一背景下&#xff0c;直播电商系统中台架构成为了连接消费者与商品的智能纽带&a…

【STM32+HAL+Proteus】系列学习教程---串口USART(DMA 方式)定长,不定长收发。

实现目标 1、利用UART实现上位机PC与下位机开发板之间的数据通信 2、学会STM32CubeMX软件关于UART的DMA模式配置 3、具体目标&#xff1a;1、实现串口定长收发数据通信&#xff1b;2、串口不定长收发数据通信。 一、DMA简介 1、什么是DMA? DMA&#xff08;Direct Memory …

yolo-驾驶行为监测:驾驶分心检测-抽烟打电话检测

在现代交通环境中&#xff0c;随着汽车技术的不断进步和智能驾驶辅助系统的普及&#xff0c;驾驶安全成为了公众关注的焦点之一 。 分心驾驶&#xff0c;尤其是抽烟、打电话等行为&#xff0c;是导致交通事故频发的重要因素。为了解决这一问题&#xff0c;研究人员和工程师们…

MySQL索引为什么选择B+树,而不是二叉树、红黑树、B树?

12.1.为什么没有选择二叉树&#xff1f; 二叉树是一种二分查找树&#xff0c;有很好的查找性能&#xff0c;相当于二分查找。 二叉树的非叶子节值大于左边子节点、小于右边子节点。 原因&#xff1a; 但是当N比较大的时候&#xff0c;树的深度比较高。数据查询的时间主要依赖于…

算法学习笔记Day8——回溯算法

本文解决几个问题&#xff1a; 回溯算法是什么&#xff1f;解决回溯算法相关的问题有什么技巧&#xff1f;回溯算法代码是否有规律可循&#xff1f; 一、介绍 1.回溯算法是什么&#xff1f; 回溯算法就是个多叉树的遍历问题&#xff0c;关键在于在前序和后序时间点做一些操作…

wps屏幕录制怎么用?分享使用方法!

数字化时代&#xff0c;屏幕录制已成为我们学习、工作和娱乐中不可或缺的一部分。无论是制作教学视频、分享游戏过程&#xff0c;还是录制网络会议&#xff0c;屏幕录制都能帮助我们轻松实现。WPS作为一款功能强大的办公软件&#xff0c;其屏幕录制功能也备受用户青睐。本文将详…

CentOS-7安装Mysql并允许其他主机登录

一、通用设置&#xff08;分别在4台虚拟机设置&#xff09; 1、配置主机名 hostnamectl set-hostname --static 主机名2、修改hosts文件 vim /etc/hosts 输入&#xff1a; 192.168.15.129 master 192.168.15.133 node1 192.168.15.134 node2 192.168.15.136 node33、 保持服…

day13 ts后端持久层框架(java转ts全栈/3R教室)

简介&#xff1a;如果说TS全栈后端开发最重要的两个框架&#xff0c;除了nestjs就是持久层框架了&#xff0c;这里主要看下Typeorm&#xff08;java中常用的就是mybatis&#xff0c;springdatajpa&#xff0c;hebernite了&#xff09; 先回顾下ORM的概念&#xff1a;ORM就是建…

C# GetField 方法应用实例

目录 关于 C# Type 类 GetField 方法应用 应用举例 心理CT设计题 类设计 DPCT类实现代码 小结 关于 C# Type 类 Type表示类型声明&#xff1a;类类型、接口类型、数组类型、值类型、枚举类型、类型参数、泛型类型定义&#xff0c;以及开放或封闭构造的泛型类型。调用 t…

二叉树的性质

性质一:二叉树的第i层上最多有2^(i-1) 个节点 性质二:深度为k的二叉树最多有2^(k)-1个节点 等比数列求和公式: 直接套进去就得到 2^(k)-1 (结点的度&#xff08;Degree) &#xff1a;结点子树的个数。树的度&#xff1a; 树中结点的最大度数。度为k的树也称为k叉树) 性质三:叶…

Uptime Kuma 使用指南:一款简单易用的站点监控工具

我平时的工作会涉及到监控&#xff0c;而站点是一个很重要的监控项。项目上线后&#xff0c;我们通常会将站点监控配置到云平台上&#xff0c;以检测各站点的连通性。但随着项目不断增多&#xff0c;云平台上的配额就有点捉急了。针对这个情况&#xff0c;我们可以试试这个开源…