【Java EE 初阶】如何保证线程安全

news2024/10/6 5:57:25

目录

 

1.线程是什么?

2.线程安全(重点)

1.概念:

1.举例:用两个线程分别对同一个变量做五万次自增,观察答案是否符合预期

那么是哪些原因造成了这种线程不安全的现象呢?我们一起来分析一下:

1.多个线程修改了同一个变量

2.线程在CPU调度上是抢占式执行的

3.没有保证线程的原子性

 4.内存可见性

JAVA内存模型JVM是什么?

为什么要用JVM呢?

 5.代码的有序性

我们来总结一下造成线程不安全的原因主要有哪些? 

3.解决线程不安全问题(Synchronized关键字-监视器锁)

核心代码展示:对count自增的方法上锁

结果展示:

4.Synchronized关键字的注意事项

在JAVA虚拟机中,对象在内存中的结构可以划分为4部分区域

5.Synchronized的使用


 

1.线程是什么?

Thread是Java中的类,PCB是系统中真正的线程

调用start()方法才会真正的去系统中申请一个线程

线程的状态有哪些? 

d41fca42e3e7489ba7a0b99610e551f8.png

2.线程安全(重点)

1.概念:

如果多线程环境下代码运行的结果与单线程环境下相同,则说明这个线程是安全的

1.举例:用两个线程分别对同一个变量做五万次自增,观察答案是否符合预期

5ceb8680f07a47728236b788ea575f40.png

可以看见结果并不是我们所想的100000

那么是哪些原因造成了这种线程不安全的现象呢?我们一起来分析一下:

1.多个线程修改了同一个变量

2.线程在CPU调度上是抢占式执行的

3.没有保证线程的原子性

原子性就是一段代码,要么全部执行成功,要么全部执行失败

我们知道,代码最终都会编译成CPU可以执行的指令,那么count++这一条指令其实对应着三步操作:

1.从内存把数据读到CPU

2.进行数据更新

3.把数据写回CPU

那么为什么不保证原子性就会出错呢?首先这和线程的抢占式执行密切相关

我们来举个例子:

分别有两个线程对count这个变量进行自增操作t1和t2,count初始值为0

假设t2先从内存把数据读到CPU,此时CPU被t1抢占了过去,t1开始从内存把数据读到CPU并对count进行了自增操作:count++,此时t2又把CPU抢占了回来,也对count进行了自增操作,count++,此时又回到t1,将数据写回CPU,count = 1,然后t2也进行了数据的写回,count= 1;现在我们可以发现问题了,由于没有保证原子性,导致多个线程之间进行了重复的自增操作,覆盖掉别的线程修改后的值,所以最终的结果不对

图解如下:

9108dca3deb5480389d37aefb027435a.png

 4.内存可见性

在多线程环境下,某一个线程修改了共享的变量,其他线程不能及时地接收到最新的值

JAVA内存模型JVM是什么?

99cfac92f5474ccbbbc608e91c326167.png

1.主内存:指的是硬件的内存条,进程在启动的时候会申请一些资源,包括内存资源,用来保存所有的变量

2.工作内存:指的是线程独有的内存空间,它们之间不能相互访问,起到了线程之间内存隔离的作用

3.JVM规定,一个线程在修改某个变量的时候,必须把这个变量从主内存加载到自己的工作内存,修改完成后在返回主内存

为什么要用JVM呢?

Java是一个跨平台语言,而JVM把不同的计算设备和操作系统对内存的管理做了一个统一的封装

 5.代码的有序性

是指在编译过程中,JVM调用本地接口,CPU执行指令的过程中,指令的有序性

3eb28da366b0425fb8009f12740941a2.png

 这种通过打乱顺序,把不相关的代码或指令重新排列,从而提高程序效率的方式,在程序中叫做指令重排序

在单线程中重排序之后的结果百分百正确,但在多线程环境下就未必了

我们来总结一下造成线程不安全的原因主要有哪些? 

f08d9ab219284248948289b514036d13.png

3.解决线程不安全问题(Synchronized关键字-监视器锁)

对当前执行的代码加锁

当某一个线程要执行这个方法时,就先获取锁,获取到锁之后再去执行代码,其他线程也需要执行这个方法时,也需要获取锁,但是已经有线程持有锁时,他就需要等待,等到上一个线程释放这把锁(注意分辨锁的释放与CPU调度的区别,只有锁被释放之后,其他线程才能竞争锁,否则一直需要等待,且CPU的调用调离与释放锁没有任何关系)之后才有可能竞争到CPU的调度

因为线程时抢占式执行,CPU对调度是随机的,并不是先阻塞等待的线程就一定会先拿到锁

我们发现上了锁之后的代码变成了单线程,这也是不可避免的

所以在获取数据时,我们用多线程来提高效率

在修改数据时,用Synchronized上锁来保证安全

核心代码展示:对count自增的方法上锁

public synchronized void increase() {
        count++;
    }

结果展示:

c6e944af48db4912a2434172b544cb77.png

可以看见上锁之后结果正确了,说明Synchronized解决了原子性的问题,并且通过把并行操作变成了串行操作,也保证了内存的可见性

但是Synchronized并不能保证有序性

4.Synchronized关键字的注意事项

1.从并行到串行:首先要保证正确,然后才考虑效率

2.加锁与CPU调度:锁的释放与CPU调度的区别,只有锁被释放之后,其他线程才能竞争锁,否则一直需要等待,且CPU的调用调离与释放锁没有任何关系

3.加锁的范围:比如加在for循环外就与串行是一模一样的,但加在外面两个for循环之间就是并发执行的,这样写要比两个for循环分别执行要快很多,这个要跟及实际情况考虑,加锁的范围越大称锁的粒度越大,反之越小

4.给代码块加锁:Synchronized可以用来修饰代码块,此时需要传入一个参数,用来表明锁的对象

5.锁对象:竞争的锁都必须是针对同一个对象的,可以自定义一个单独的对象表示锁(可以是JAVA中的任何对象),也可以使用this,多线程并不关心锁的对象是哪个,只关心他们是否竞争同一把锁,也就是是否是同一个对象,只有同一个对象才会产生锁的竞争

在JAVA虚拟机中,对象在内存中的结构可以划分为4部分区域

  • mark word 与 类型指针(_class)  这两部分统一称为对象头 主要描述了当前是哪个线程获取到的资源,记录的是线程对象信息,当线程释放所资源的时候就会把线程对象信息清除掉,其他的线程就可以继续获得锁资源
  • 实例数据 保存的就是类中的属性
  • 对其填充 每一个类对象占用的字节数必须是八字节的整数倍

5.Synchronized的使用

6b8be3966b7e498686174e6e9c20af7b.png

 989469be810641a8a640f19b329e0705.png

 

 

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

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

相关文章

搭建Plex媒体服务器,打造家庭多媒体中心【公网远程访问】

文章目录 1.前言2. Plex网站搭建2.1 Plex下载和安装2.2 Plex网页测试2.3 cpolar的安装和注册 3. 本地网页发布3.1 Cpolar云端设置3.2 Cpolar本地设置 4. 公网访问测试5. 结语 1.前言 用手机或者平板电脑看视频,已经算是生活中稀松平常的场景了,特别是各…

MAC安装MySQL

安装MySQL 登录官网dev.mysql.com/downloads/m… 下载社区版mysql,选择dmg格式的安装包。下载完成后,开始安装。 注意:选择Use Legacy Password Encryption。 解决无法启动MySQL问题 打开设置中的mysql图标,发现红点&#xff0…

Syslog-ng RHEL 的安装和配置

syslog-ng 作为 syslog 的替代工具,可以完全替代 syslog 的服务,并且通过定义规则,实现更好的过滤功能。 作为运维来说一个好的日志工具比什么都重要。 通常我们会管理不同的服务器,因此我们需要把日志集中一下以便于快速查找。…

GUI编程(二)

Swing Swing是GUI(图形用户界面)开发工具包。 早期的AWT(抽象窗口工具包)组件开发的图形用户界面,要依赖本地系统,当把AWT组件开发的应用程序移植到其他平台的系统上运行时,不能保证其外观风格…

贪心刷题~

1、洛谷P2240 【深基12.例1】部分背包问题 贪心策略&#xff1a;拿金币单价高的。 #include<iostream> #include<cstring> #include<algorithm> using namespace std;struct gold{int v;int m; } q[101];bool cmp(gold a,gold b){return a.v*b.m>b.v*a.m…

SpringCloud-微服务Eureka服务注册中心

微服务&服务注册中心 前言一、微服务1.什么是微服务2.单体架构和微服务架构2.1.单体架构2.2.微服务架构 二、服务注册中心1.服务注册中心简介2.Eureka服务注册中心2.1.Eureka Server开发2.2 Eureka Client开发 3.Eureka的自我保护机制3.1.Eureka自我保护机制简介3.2.Eureka…

MySQL数据库连接超时自动断开的解决方案

这里写自定义目录标题 欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题&#xff0c;有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants 创建一个自定义列表如何创建一个…

windows下msys2编译64位的ffmpeg源码

目前遇到过两次需求&#xff0c;需要编译ffmpeg源码。网上下载的编译好的源码里面可能不全&#xff0c;很多时候需要自行编译源码。本文介绍自行编译ffmpeg64位源码&#xff08;32位通过相似的方式为编译成功&#xff0c;不知道原因&#xff09; 环境&#xff1a; 2023.5.4下载…

团队密码管理器Passbolt的安装

老苏下载了吴恩达联手 OpenAI 推出的 Prompt for developer 课程&#xff0c;总长度大概在一个半小时左右&#xff0c;可以让我们学习正确的 ChatGPT Prompt 工程 虽然课程对话是英文&#xff0c;但有中文字幕&#xff0c;课程地址&#xff1a;https://www.aliyundrive.com/s/…

[Gitops--9]微服务项目sangomall代码配置修改及资源清单文件

微服务项目sangomall代码配置修改及资源清单文件 1. 中间件的地址 1.1 Nacos 集群外 nacos-server.intra.com 192.168.31.211集群内 nacos-server.sangomall.svc.cluster.local. nacos-server.sangomall.svc.cluster.local.:88481.2 Redis 集群内 redis.sangomall.svc.c…

ipad有必要用手写笔吗?电容笔和Apple pencil区别

与Apple Pencil最大的不同之处&#xff0c;在于普通的电容笔并不具备着重力压感&#xff0c;而是会给人一种倾斜的压感。如果不是频繁作画&#xff0c;那就用一支普通的电容笔。这种电容笔不但可以用于办公室&#xff0c;也可以用于记笔记、做练习。再说了&#xff0c;一支苹果…

深入理解 Linux 内核(二)

系列文章目录 Linux 内核设计与实现 深入理解 Linux 内核 深入理解 Linux 内核&#xff08;二&#xff09; Linux 设备驱动程序 Linux设备驱动开发详解 文章目录 系列文章目录五、定时测量1、时钟和定时器电路2、Linux 计时体系结构&#xff08;1&#xff09;计时体系机构的数据…

200G 400G光模块介绍

200G 光模块封装有2种&#xff0c;分别是QSFP56和QSFP-DD。 200G QSFP56有2种光模块&#xff0c;第一种是200G QSFP56 SR4&#xff0c;第二种是200G QSFP56 FR。 200G QSFP56 SR4的封装形式是QSFP56&#xff0c;速率是200G&#xff0c;波长是850nm&#xff0c;最远传输距离是10…

儿童书写台灯哪个牌子比较好?盘点护眼学生用台灯品牌排行

想要拥有一个健康的视力对于我们多么重要&#xff0c;日常生活多么不便利&#xff0c;就是像家里孩子考学时视力也是对于未来专业选择的一个阻碍。 想要孩子不吃近视的苦&#xff0c;从小就要开始抓孩子对于视力和眼睛的呵护。 养成好习惯必须保持一个正确的学习姿势&#xff…

redis 持久化 RDB + AOF

redis 持久化 RDB AOF 1.redis持久化----两种方式 RDB&#xff08;Redis DataBase&#xff09;和AOF&#xff08;Append Only File&#xff09; RDB&#xff0c;简而言之&#xff0c;就是在不同的时间点&#xff0c;将redis存储的数据生成快照并存储到磁盘等介质上 AOF&am…

视频剪辑学习 pr 中视频

2023年中视频学习计划&#xff0c;学习资料全套视频。全网一手资料&#xff0c;有意者V&#xff1a; 第一章- 基础知识 第二章- 素材获取 第三章- 文案创作及搬运改写 第四章- 智能配音与自己配音修音 第五章- 剪辑基础快速入门 手机剪映零基础快速入门 电脑剪映零基础快速入门…

360SEO 360搜索引擎算法的基础知识

360搜索引擎是中国的一家互联网搜索引擎公司&#xff0c;由奇虎360公司推出。作为中国互联网领域的知名品牌之一&#xff0c;它的搜索算法一直备受关注和研究。那360搜索引擎有哪些算法的基础知识呢&#xff1f; 一、概述 360搜索引擎算法是一个非常庞大、复杂的系统&#xff…

科研人的利器:利用New Bing五分钟读完一篇论文

大家好&#xff0c;我是可夫小子&#xff0c;关注AIGC、读书和自媒体。解锁更多ChatGPT、AI绘画玩法。加我&#xff0c;拉你进群。 New Bing『新必应』是微软一款集成了ChatGPT的搜索引擎&#xff0c;它以聊天的方式来进行信息搜索&#xff0c;这不同过去几十年通过对话框搜索信…

Linux之yum原(三)

最近学习Linux&#xff0c;利用 yum 下载软件的时候&#xff0c;总是报错&#xff1a; 错误&#xff1a;为仓库 appstream 下载元数据失败 : Cannot prepare internal mirrorlist: No URLs in mirrorlist因此小编决定更换一下 yum 源&#xff0c;小编用的是 CentOS8.5.2111&am…

Scala Option类型,异常处理,IO,高阶函数

Option类型 实际开发中, 在返回一些数据时, 难免会遇到空指针异常(NullPointerException), 遇到一次就处理一次相对来讲还是比较繁琐的. 在Scala中, 我们返回某些数据时&#xff0c;可以返回一个Option类型的对象来封装具体的数据&#xff0c;从而实现有效的避免空指针异常。S…