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

Java线程 - 详解(2)

一,线程安全问题

有些代码在单个线程的环境下运行,完全正确,但是同样的代码,让多个线程去执行,此时就可能出现BUG,这就是所谓的 "线程安全问题"。举一个例子:

public class Demo {static int count = 0;public static void main(String[] args) throws InterruptedException {Thread thread = new Thread(()->{for (int i = 0; i < 5000; i++) {count++;}});Thread thread1 = new Thread(()->{for (int i = 0; i < 5000; i++) {count++;}});thread.start();thread1.start();thread.join();thread1.join();System.out.println("count = "+count);}
}

 以上代码如果使用单线程执行,他的答案是10000,但是如果使用多线程,那么就不确定了。

 那么为什么会出现这种情况呢?首先我们要深入了解一下 count++ 这个操作,实际上这个操作是分成 3 步执行的(站在CPU的角度,count++,是有三个指令实现的):

  1. load 把数据从内存读取到 CPU 寄存器中   ——>  tmp = count (简单理解版)
  2. add 把寄存器中的数据进行 +1                   ——>  tmp += 1      (简单理解版)
  3. save 把寄存器中的数据,保存到内存中    ——>  count = tmp  (简单理解版)

在此基础上,又因为线程之间的调度顺序是随机的,就会导致上面的代码出BUG,画一个图来理解一下:

 (上面画的只是一部分情况),也就是说,两个线程分别自增一次,预期得到的是2,实际上可能得到的是1,这就会导致两个线程的结果没有向上累加,而是各自独立运行。

讲了上面的BUG后,还有一个问题,我们得到的count的可能取值范围是多少?是[1,10000],还是[5000,10000]?答案是 [1,10000],因为可能 线程1 自增1次, 而 线程2 自增 n 次,画个图理解一下:

 二,线程安全问题产生原因

1. 操作系统中,线程的调度顺序是随机的(抢占式执行)

        线程的调度顺序是在系统内核实现的,无法解决

2. 两个线程,针对同一个变量进行修改​​​​​​​

        一个线程针对一个变量进行修改 ✔️

        两个线程针对不同变量进行修改 ✔️

        两个线程针对同一个变量进行读取 ✔️

3. 修改操作不是原子的,拿上面的举例就是:count++这个操作不是一步到位的,需要分成4三步执行。

        原子性:将多个操作"封装"起来,使其就相当于一个操作,更加通俗一点,就相当于

        有一个房间,当线程1在该房间执行操作时,线程2要么等待,要么去其他房间执行

4. 内存可见性问题(这章还不涉及)

5. 指令重排序问题(这章还不涉及)

 三,解决线程安全问题

上面讲了5种原因导致线程安全问题,其中1是避免不了的,2是只能在写代码时尽量避免,4,5还没涉及到,因此我们要想解决线程安全问题就只能从原因3入手,即将那些非原子操作转换成原子操作,更加专业一点就是 "加锁"。

在Java中,给代码"加锁"最常见的办法就是使用 synchronized 关键字:

synchronized( ){

        ......

        //要执行的操作放在这里

}

注:( )中需要一个用来加锁的对象。这个对象的类型不重要,重要的是通过这个对象来区分两个线程是否竞争同一个锁,如果两个线程是在竞争同一个锁,就会有锁竞争,如果不是,就不会有锁竞争,就任然是并发执行。

你可以将锁想象成一个单人的自习室,如果你先占用了这个自习室,那么其他人要么阻塞等待你使用结束(锁竞争),要么去其他空的自习室(没有锁竞争)。

public class Demo {static int count = 0;public static void main(String[] args) throws InterruptedException {Object locker = new Object();//锁Thread thread = new Thread(()->{synchronized (locker){for (int i = 0; i < 5000; i++) {count++;}}});Thread thread1 = new Thread(()->{synchronized (locker){for (int i = 0; i < 5000; i++) {count++;}}});thread.start();thread1.start();thread.join();thread1.join();System.out.println("count = "+count);}
}

 在画个图对比一下:

相关文章:

Java线程 - 详解(2)

一&#xff0c;线程安全问题 有些代码在单个线程的环境下运行&#xff0c;完全正确&#xff0c;但是同样的代码&#xff0c;让多个线程去执行&#xff0c;此时就可能出现BUG&#xff0c;这就是所谓的 "线程安全问题"。举一个例子&#xff1a; public class Demo {s…...

事务特性 - 达梦数据库

达梦数据库事务特性 1 事务特性1.1 原子性1.2 一致性1.3 隔离性1.4 持久性 1 事务特性 事务必须具备什么属性才是一个有效的事务呢&#xff1f;一个逻辑工作单元必须表现出四种属性&#xff0c;即原子性、一致性、隔离性和持久性&#xff0c;这样才能成为一个有效的事务。DM 数…...

axios 使用FormData格式发送GET请求

如果你需要使用&#xff0c;FormData格式&#xff0c;发送GET请求 将参数拼接到 FormData对象 中&#xff0c;使用 URLSearchParams 将FormData对象转换为查询参数字符串&#xff0c;并将其拼接到URL中&#xff0c;这样就能以FormData格式发送GET请求给服务器 注意&#xff1…...

CS144(2023 Spring)Lab 1: stitching substrings into a byte stream

文章目录 前言其他笔记相关链接 1. Getting started2. Putting substrings in sequence2.1 需求分析2.2 注意事项2.3 代码实现 3. 测试与优化 前言 这一个Lab主要是实现一个TCP receiver的字符串接收重组部分。 其他笔记 Lab 0: networking warmup Lab 1: stitching substri…...

【PHP】常用的PHP内置函数

1、PHP内置函数非常丰富&#xff0c;用于执行各种任务。以下是一些常用的PHP内置函数&#xff1a; 字符串操作函数&#xff1a; strlen(): 返回字符串的长度。 strpos(): 查找字符串中的某个子串第一次出现的位置。 substr(): 返回字符串的子串。 str_replace(): 替换字符串中的…...

css自学框架之消息弹框

首先我们还是看看消息弹框效果&#xff1a; 主要实现代码分为三部分 一、CSS部分&#xff0c;这部分主要是定义样式&#xff0c;也就是我们看到的外表&#xff0c;主要代码&#xff1a; /* - 弹窗 */notice{top: 0;left: 0;right: 0;z-index: 10;padding: 1em;position: fix…...

42、Flink 的table api与sql之Hive Catalog

Flink 系列文章 1、Flink 部署、概念介绍、source、transformation、sink使用示例、四大基石介绍和示例等系列综合文章链接 13、Flink 的table api与sql的基本概念、通用api介绍及入门示例 14、Flink 的table api与sql之数据类型: 内置数据类型以及它们的属性 15、Flink 的ta…...

PAT 1145 Hashing - Average Search Time

个人学习记录&#xff0c;代码难免不尽人意。 The task of this problem is simple: insert a sequence of distinct positive integers into a hash table first. Then try to find another sequence of integer keys from the table and output the average search time (the…...

C++调用Python Win10 Miniconda虚拟环境配置

目录 前言1. Win10 安装 Miniconda2. 创建虚拟环境3. 配置C调用python环境4. C调用Python带参函数5.遇到的问题6. 总结 前言 本文记录了Win10 系统下Qt 应用程序调用Python时配置Miniconda虚拟环境的过程及遇到的问题&#xff0c;通过配置Python虚拟环境&#xff0c;简化了Qt应…...

从0到1学会Git(第一部分):Git的下载和初始化配置

1.Git是什么: 首先我们看一下百度百科的介绍:Git&#xff08;读音为/gɪt/&#xff09;是一个开源的分布式版本控制系统&#xff0c;可以有效、高速地处理从很小到非常大的项目版本管理。 也是Linus Torvalds为了帮助管理Linux内核开发而开发的一个开放源码的版本控制软件。 …...

【记录】手机QQ和电脑QQ里的emoji种类有什么差异?

版本 手机 QQ&#xff1a;V 8.9.76.12115 电脑 QQ&#xff1a;QQ9.7.15&#xff08;29157&#xff09; 偶然发现&#xff0c;有一种emoji手机上怎么找都找不到&#xff0c;一开始以为自己失忆了&#xff0c;后来发现这种emoji只在电脑上有。 接下来简单说一下找emoji差异的方式…...

blender界面认识01

学习视频 【基础篇】1.2 让手听话_哔哩哔哩_bilibili 目录 控制视角 控制物体 选择对象1 小结 控制视角 长按鼠标中键-----视角旋转 shift鼠标中键-----视角平移 滚动鼠标中键-----视角缩放 也可以通过界面的快捷工具实现 这个视角旋转有一点像catia中罗盘&#xff0c…...

TCP数据报结构分析(面试重点)

在传输层中有UDP和TCP两个重要的协议&#xff0c;下面将针对TCP数据报的结构进行分析 关于UDP数据报的结构分析推荐看UDP数据报结构分析&#xff08;面试重点&#xff09; TCP结构图示 TCP报头结构的分析 一.16位源端口号 源端口表示发送数据时&#xff0c;发送方的端口号&am…...

合并两个有序的单链表,合并之后的链表依然有序

定义节点 class ListNode {var next: ListNode _var x: Int _def this(x: Int) {thisthis.x x}override def toString: String s"x>$x" } 定义方法 class LinkedList {var head new ListNode(0)def getHead(): ListNode this.headdef add(listNode: Li…...

eureka迁移到nacos--双服务中心注册

服务注册中心的迁移有多种方式&#xff0c;官网使用nacos sync&#xff0c;还有民间开发的双注册中心组件eureka-nacos-proxy&#xff0c;但是我用了不太顺利&#xff0c;所以用的是阿里巴巴的双注册中心组件edas-sc-migration-starter spring boot&#xff1a;2.5.3 引入依赖 …...

线程池使用不规范导致线程数大以及@Async的规范使用

文章详细内容来自&#xff1a;线程数突增&#xff01;领导&#xff1a;谁再这么写就滚蛋&#xff01; 下面是看完后文章的&#xff0c;一个总结 线程池的使用不规范&#xff0c;导致程序中线程数不下降&#xff0c;线程数量大。 临时变量的接口&#xff0c;通过下面简单的线…...

启莱OA treelist.aspx SQL注入

子曰&#xff1a;“为政以德&#xff0c;譬如北辰&#xff0c;居其所&#xff0c;而众星共之。” 漏洞复现 访问漏洞url&#xff1a; 使用SQLmap对参数 user 进行注入 漏洞证明&#xff1a; 文笔生疏&#xff0c;措辞浅薄&#xff0c;望各位大佬不吝赐教&#xff0c;万分感…...

ES是一个分布式全文检索框架,隐藏了复杂的处理机制,核心数据分片机制、集群发现、分片负载均衡请求路由

ES是一个分布式框架&#xff0c;隐藏了复杂的处理机制&#xff0c;核心数据分片机制、集群发现、分片负载均衡请求路由。 ES的高可用架构&#xff0c;总体如下图&#xff1a; 说明&#xff1a;本文会以pdf格式持续更新&#xff0c;更多最新尼恩3高pdf笔记&#xff0c;请从下面…...

xml和json互转工具类

分享一个json与xml互转的工具类&#xff0c;非常好用 一、maven依赖 <!-->json 和 xm 互转</!--><dependency><groupId>org.dom4j</groupId><artifactId>dom4j</artifactId><version>2.1.3</version></dependency&g…...

Windows系统下MMDeploy预编译包的使用

Windows系统下MMDeploy预编译包的使用 MMDeploy步入v1版本后安装/使用难度大幅下降&#xff0c;这里以部署MMDetection项目的Faster R-CNN模型为例&#xff0c;将PyTorch模型转换为ONNX进而转换为Engine模型&#xff0c;部署到TensorRT后端&#xff0c;实现高效推理&#xff0c…...

【网络】每天掌握一个Linux命令 - iftop

在Linux系统中&#xff0c;iftop是网络管理的得力助手&#xff0c;能实时监控网络流量、连接情况等&#xff0c;帮助排查网络异常。接下来从多方面详细介绍它。 目录 【网络】每天掌握一个Linux命令 - iftop工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景…...

深入剖析AI大模型:大模型时代的 Prompt 工程全解析

今天聊的内容&#xff0c;我认为是AI开发里面非常重要的内容。它在AI开发里无处不在&#xff0c;当你对 AI 助手说 "用李白的风格写一首关于人工智能的诗"&#xff0c;或者让翻译模型 "将这段合同翻译成商务日语" 时&#xff0c;输入的这句话就是 Prompt。…...

边缘计算医疗风险自查APP开发方案

核心目标:在便携设备(智能手表/家用检测仪)部署轻量化疾病预测模型,实现低延迟、隐私安全的实时健康风险评估。 一、技术架构设计 #mermaid-svg-iuNaeeLK2YoFKfao {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg…...

CocosCreator 之 JavaScript/TypeScript和Java的相互交互

引擎版本&#xff1a; 3.8.1 语言&#xff1a; JavaScript/TypeScript、C、Java 环境&#xff1a;Window 参考&#xff1a;Java原生反射机制 您好&#xff0c;我是鹤九日&#xff01; 回顾 在上篇文章中&#xff1a;CocosCreator Android项目接入UnityAds 广告SDK。 我们简单讲…...

【决胜公务员考试】求职OMG——见面课测验1

2025最新版&#xff01;&#xff01;&#xff01;6.8截至答题&#xff0c;大家注意呀&#xff01; 博主码字不易点个关注吧,祝期末顺利~~ 1.单选题(2分) 下列说法错误的是:&#xff08; B &#xff09; A.选调生属于公务员系统 B.公务员属于事业编 C.选调生有基层锻炼的要求 D…...

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 位数字。 输…...

Mobile ALOHA全身模仿学习

一、题目 Mobile ALOHA&#xff1a;通过低成本全身远程操作学习双手移动操作 传统模仿学习&#xff08;Imitation Learning&#xff09;缺点&#xff1a;聚焦与桌面操作&#xff0c;缺乏通用任务所需的移动性和灵活性 本论文优点&#xff1a;&#xff08;1&#xff09;在ALOHA…...

中医有效性探讨

文章目录 西医是如何发展到以生物化学为药理基础的现代医学&#xff1f;传统医学奠基期&#xff08;远古 - 17 世纪&#xff09;近代医学转型期&#xff08;17 世纪 - 19 世纪末&#xff09;​现代医学成熟期&#xff08;20世纪至今&#xff09; 中医的源远流长和一脉相承远古至…...

人工智能(大型语言模型 LLMs)对不同学科的影响以及由此产生的新学习方式

今天是关于AI如何在教学中增强学生的学习体验&#xff0c;我把重要信息标红了。人文学科的价值被低估了 ⬇️ 转型与必要性 人工智能正在深刻地改变教育&#xff0c;这并非炒作&#xff0c;而是已经发生的巨大变革。教育机构和教育者不能忽视它&#xff0c;试图简单地禁止学生使…...

Python Einops库:深度学习中的张量操作革命

Einops&#xff08;爱因斯坦操作库&#xff09;就像给张量操作戴上了一副"语义眼镜"——让你用人类能理解的方式告诉计算机如何操作多维数组。这个基于爱因斯坦求和约定的库&#xff0c;用类似自然语言的表达式替代了晦涩的API调用&#xff0c;彻底改变了深度学习工程…...