多线程(九):JUC组件

news2024/10/3 10:35:09

在来时juc组件前,我们先把上一章遗漏的部分给补上。

synchronized 实现策略:锁升级:

无锁 -> 偏向锁 -> 轻量级锁 -> 重量级锁 

还有一个 :

锁消除

锁消除即删除不必要的加锁操作。JVM在运行时,对一些“在代码上要求同步,但是被检测到不可能存在共享数据竞争情况”的锁进行消除。根据代码逃逸技术,如果判断到一段代码中,堆上的数据不会逃逸出当前线程,那么就可以认为这段代码是线程安全的,无需加锁。

就是在编译阶段 做的优化手段 ~~ 检测到当前代码是否是在多线程状态下运行的 / 是否有必要去进行加锁操作!如果是不必要的,但是又把锁加上了,那么 在编译过程中就会自动把锁去掉。

锁粗化

我们之前了解了锁的粒度:描述被synchronized 修饰的代码块的长度;   

假设一系列的连续操作都会对同一个对象反复加锁及解锁,甚至加锁操作是出现在循环体中的,即使没有出现线程竞争,频繁地进行互斥同步操作也会导致不必要的性能损耗。

如果JVM检测到有一连串零碎的操作都是对同一对象的加锁,将会扩大加锁同步的范围(即锁粗化)到整个操作序列的外部。

我们来画个图:

 在写代码时反复的加锁,编译器就对其进行优化,直接优化为从第一次加锁开始直到最后一次释放锁才释放。

Callable 接口

callable 是线程实现的方法之一:

它与之前三种的区别在于:

callable可以有返回值,也可以抛出异常的特性,而Runnable等没有。

它的用法类似于 Runnable ;

例如:

实现1 到 1000 的加法: 

这是我们不能像Runnable 方法一样直接放到 Thread 类中,我们还需要一个中转类:

FutureTask 类。

这里就好比我们点完餐后领取一个小票,没有这个小票我们就不能去领餐了。

这里的call 方法被 Thread 这个线程调用。

那么现在我们就可以总结一下我们可以实现线程的四个方法了:

1.  实现Thread 类

2.  继承Runnable 接口(本质都是重写run 方法)

3.  基于lambda 表达式(Lambda 表达式描述了一个代码块(或者叫匿名方法),可以将其作为参数传递给构造方法或者普通方法以便后续执行)

4.  实现Callable 接口

那么接下来正式开始本章的内容:

常见的 JUC 组件,这个组件就认识认识就好,都不需要背,需要的时候查找一下即可。

JUC 即 java.util.concurrent 的缩写。

ReentrantLock

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

synchronized 是个关键字,进入被synchronized 修饰的代码块即被加锁,除了 代码块即解锁。

而 ReentrantLock 类提供了 lock 和 unlock 方法来进行加锁解锁。

我们大部分的情况下使用 synchronized 就够用了,ReentrantLock 是一个重要的补充。

ReentrantLock 和 synchronized 的区别:

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

原子类

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

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

具体的案例这里就不实现了。

信号量 Semaphore

信号量, 用来表示 "可用资源的个数". 本质上就是一个计数器

这里有个PV操作,PV是荷兰语申请资源和释放资源 单词的缩写。

P 操作申请资源 计数器 - 1

V 操作释放资源 计数器 +1

如果此时 计数器为0 ,那么继续申请资源就会阻塞等待。

而我们所谓的 锁 ;本质上就是个 计数器为1信号量。

而信号量是个广义的锁,不光能管理 0 和 1 的信号量还能管理多个资源。

具体的代码不过多演示,可以直接查。

CountDownLatch

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

这个就好像赛马:只有等每匹马都跑过终点了,才会公布成绩。

使用场景:

下载大文件:几十个 GB,我们单线程下载耗时非常长,那么就可以选择多线程下载;

我们把文件分成多份,每个线程只负责自己那部分文件的下载。

只有当最后一部分文件被下载完了才算下载完成。

线程安全的集合类(重点)

我们在数据结构中学过那么多集合类,其中大部分集合类都是线程不安全的;

只有 :Vector, Stack, HashTable, 是线程安全的(但不建议用), 其他的集合类不是线程安全的

如果需要在多线程下使用怎么办呢,直接加一个 synchronized 修饰(加锁)即可。

需要用到 ArrayList

简单介绍几个:

要用 ArrayList 时直接套壳即可。

 CopyOnWriteArrayList(写实拷贝集合类)

  1.  当我们往一个容器添加元素的时候,不直接往当前容器添加,而是先将当前容器进行Copy,复制出一个新的容器,然后新的容器里添加元素,
  2. 添加完元素之后,再将原容器的引用指向新的容器

这样做的好处是我们可以对CopyOnWrite容器进行并发的读,而不需要加锁,因为当前容器不会
添加任何元素。

优点:

  1. 在读多写少的场景下, 性能很高, 不需要加锁竞争

缺点:

  1.  占用内存较多.
  2. 新写的数据不能被第一时间读取
     

多线程环境使用哈希表

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

  1. Hashtable
  2. ConcurrentHashMap
     

Hashtable 安全的原因是:只是简单的把关键方法加上了 synchronized 关键字:

而我们还有一个类: ConcurrentHashMap

ConcurrentHashMap 和 Hashtable 的区别 (高频面试题)

对比而言,ConcurrentHashMap  相当于 Hashtable  的优化版本;

1. 加锁粒度不同(触发锁冲突的频率)

        Hashtable 是针对整个哈希表加锁的,任何一个增删改查的操作都会触发加锁,也就是会触发锁竞争。 如图:

ConcurrentHashMap  不是只有一把锁,每个链表(头结点)作为一把锁,每次进行操作,都是针对对应的锁进行加锁;
此时操作不同链表就是针对不同的锁加锁,不产生锁冲突
这样导致大部分加锁操作实际上没有锁冲突!

此时这里的加锁操作的开销就很低了 。

如图:

这是 Java8 提出来的,在之前Java1.7 即其以前采用 “分段锁”;目的和上述相似,但是是多个链表共用一把锁。

2. 充分利用 CAS 特性. 比如 获取元素个数,可以用size 属性通过 CAS 来更新. 避免出现重量级锁的情况.

3. 优化了扩容方式: 化整为零
发现需要扩容的线程, 只需要创建一个新的数组, 同时只搬几个元素过去.
扩容期间, 新老数组同时存在.
后续每个来操作 ConcurrentHashMap 的线程, 都会参与搬家的过程. 每个操作负责搬运一小
部分元素.
搬完最后一个元素再把老数组删掉.
这个期间, 插入只往新数组加.
这个期间, 查找需要同时查新数组和老数组

好,聊到这里我们的多线程就可以告一段落了,后面还会经常用到多线程,多线程是结束更是开始,我们后面有时间再来常见的面试题。

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

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

相关文章

C++内联函数详解

目录 如何定义内联函数? 内联函数的优势 内联函数的缺点 内联函数的使用场景 示例代码 总结 在C中,内联函数是一种特殊的函数,它的作用是在程序编译时将函数的代码直接嵌入到调用该函数的代码中,从而避免了函数调用的开销。这…

C语言 非本地跳转实现native层TryCatch

前言 最近研究native hook的技术,了解到了这个非本地跳转,本文就是介绍他,对于解决native crash非常有用。 非本地跳转介绍 C语言的本地跳转是指goto、break、continue等语句,但是这个语句最大局限就是只能实现函数内部的跳转。…

深度学习 - 40. N-Gram 采样与 Session 数据获取 For EGES

目录 一.引言 二.订单数据预处理 1.数据样例 2.订单数据处理 3.用户 Session 构建 三.构造 sku_id 游走序列 1.获取完整 Session List 2.统计 sku_id 转移词频 3.构建 sku_id 图 4.游走构造 sku 序列 四.商品侧信息预处理 1.读取商品信息 2.Left Join 匹配侧信息 …

三甲医院体检管理系统源码PEIS ,体检总检建议、体检套餐、各种模板

PEIS体检管理系统源码 本套PEIS医院体检管理系统源码,采用C#语言开发,C/S架构,前台开发工具为Vs2012,后台数据库采用oracle大型数据库。有演示。 文末获取联系 PEIS体检管理系统适用于大中型医院的独立体检中心、干部保健处、民营…

Java基础:编译时和运行时的区别

在java开发设计过程中,了解java运行时和编译时的区别非常有必要。 如下从几个问题来描述两者的区别 1、如下代码片段中,A行和B行的区别是什么 line A是在编译时计算值,line B是在运行时计算值。 当该类编译后,如果使用一些反编译…

ROS导航

参考文章: (31条消息) ROS导航小车1 teb_local_planner参数(仅作记录/收集)_teb local planner参数_Crush Mome的博客-CSDN博客 运行导航: 1. 启动底盘控制包 : base_conctronl 2.启动键盘控制节点: rosrun teleop_twist_ke…

ROG魔霸7Plus电脑一直蓝屏错误怎么重装系统?

ROG魔霸7Plus电脑一直蓝屏错误怎么重装系统?有用户在使用ROG魔霸7Plus电脑的时候,频繁的遇到了系统蓝屏的情况。因为这样影响了自己的正常使用,所以想要进行系统的重新安装。那么如何进行系统重装操作呢?来看看以下的操作方法教学…

ONES × 中国信通院《中国企业软件研发管理白皮书》即将发布 | 预约直播

由 ONES 与中国信息通信研究院联合发起的《中国企业软件研发管理白皮书》(下称「白皮书」)将于 4 月 20 日 正式发布。白皮书由 ONES、中国信息通信研究院云计算与大数据研究所、招商基金管理有限公司、紫金财产保险股份有限公司、深圳市鸿合创新信息技术…

AI大模型内卷加剧,商汤凭什么卷进来

2023年,国内大模型何其多。 目前,已宣布推出或即将推出大模型的国内企业多达20余家,基本上能想到的相关企业都已入局。其中,既有资金雄厚的BAT、华为、字节等大厂,也有王慧文、王小川、周伯文等互联网大佬领衔的初创企…

外卖小程序01

目录 nginx反向代理和负载均衡反向代理好处nginx反向代理的配置方式 负载均衡**nginx 负载均衡的配置方式:****nginx 负载均衡策略:** 动静分离 用户密码加密需求代码实现 Swagger框架介绍使用步骤常用注解使用案例:员工登录EmployeeController实体类Emp…

科研成果 | 不同调制方式的开源数据集及其数据扩增方式

文章目录 1. 数据源2. 数据扩增2.1 基于opencv的一些基础变换2.2 基于GAN网络的方法2.2.1 SinGAN2.2.2 基于多图的GAN方法1. 数据源 网址: https://www.sigidwiki.com/wiki/VHF 每种数据基本只有一条,所以要用的话只能进行数据扩征 2. 数据扩增 两种方法: 基于opencv的一…

浏览器输入 http 自动转 https 问题解决方法

目录 表象 原因 解决方案 解决方案一 解决方案二 表象 今天在开发的过程中遇到一个问题,我们项目的地址是 “http://xxx.xxx.com/website/” ,结果粘贴到浏览器里自动跳转成了 “https://xxx.xxx.com/website/”。百思不解啊,为啥呢。 …

git上如何通过本地仓库推送自己的代码到远程仓储

从gitHub或者gitee上拉取代码后,我老是想着把别人的代码保存到自己的仓库上,这里教你一招。 gitee的: 首先我们在gitee或者github上创建一个自己的仓库,github的我就不在展示了,基本上和gitee操作一样 输入相关信息…

【redis】bitmap、hyperloglog、GEO案例

【redis】bitmap、hyperloglog、GEO案例 文章目录 【redis】bitmap、hyperloglog、GEO案例前言一、面试题二、统计的类型聚合统计排序统计问题:思路 二值统计 0和1基数统计 三、hyperloglog1、名词理解UV 独立访客PV 页面浏览量DAU 日活跃用户MAU 月活跃度 2、看需求…

愚蠢的往事-网络安全专题之数字证书

血泪教训史,我被骗去办理了数字证书。 文章目录 加密算法摘要算法数字签名数字证书血泪开篇数字证书 加密算法 相关知识点:对称加密算法、非对称加密算法、信息完整性验证算法。 对称加密算法:1.加密密钥和解密密钥相同的算法,…

小行助学答题系统编程等级考试scratch三级真题2023年3月(含题库答题软件账号)

青少年编程等级考试scratch真题答题考试系统请点击 电子学会-全国青少年编程等级考试真题Scratch一级(2019年3月)在线答题_程序猿下山的博客-CSDN博客_小航答题助手 1.计算“248……128”,用变量n表示每项,根据变化规律&#xf…

SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式,系统详解springcloud微服务技术栈

http客户端Feign &#xff08;一&#xff09;基于Feign远程调用 1、RestTemplate方式调用存在的问题 2、Feign的介绍 3、定义和使用Feign客户端 这个接口里面将来的封装的就是所有对userservice发起的远程调用 1、orderserivce的pom <!--feign客户端依赖--> <depe…

Dsq: 用于针对JSON、CSV、Excel、Parquet等运行SQL查询的命令行工具

目录 About Install macOS Homebrew macOS、Linux和WSL上的二进制文件 Windows上的二进制文件&#xff08;非WSL&#xff09; 从源代码生成和安装 Usage Pretty print dsq的管道数据 多个文件和连接 无需查询即可将数据转换为JSON 嵌套在对象中的对象数组 嵌套对象…

ASRock Z690 Extreme WiFi 6E i7 13700KF电脑 Hackintosh 黑苹果efi引导文件

原文来源于黑果魏叔官网&#xff0c;转载需注明出处。&#xff08;下载请直接百度黑果魏叔&#xff09; 硬件型号驱动情况 主板ASRock Z690 Extreme WiFi 6E 处理器Intel Core i7 13700KF已驱动 内存KINGBANK 2x32GB DDR4-3600CL18已驱动 硬盘Predator SSD GM7000 1TB已驱动…

qt5.15.2配置android

qt安装安卓编译器就直接跳过&#xff0c;我们开始将如何进行配置。 如果专门开发的app&#xff0c;则应该使用android进行开发&#xff0c;qt是熟悉qt语言&#xff0c;或者app需要进行跨平台的话则使用qt for android比较好。 下载 首先安装jdk&#xff0c;最好安装 jdk11&am…