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

线程安全(JAVA)

线程安全对于我们编写多线程代码是非常重要的。

什么是线程安全?

在我们平时的代码中有些代码在单线程程序中可以正常执行,但如果同样的代码放在在多个线程中执行就会引发BUG,而这种现象我们一般称为 “线程安全问题”“线程不安全”
例如:使用两个线程对 count 变量进行自增操作,每个线程10000次。

private static int count;
public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(()->{for (int i = 0; i < 10000; i++) {count++;}});Thread t2 = new Thread(()->{for (int i = 0; i < 10000; i++) {count++;}});t1.start();t2.start();t1.join();t2.join();System.out.println(count);
}

在这里插入图片描述
结果可以看到和我们预期的并不相同,而且当我们多运行几次后,每次的结果还都不相同,这就是一个典型的 线程安全问题
为什么会出现上述情况呢?

  • 自增操作本质上其实分为三步
    – 从内存把数据读到 CPU
    – 进行加一操作
    – 把新数据写回到 CPU

  • 两个线程是并发执行

所以就会引发下面这种状况(程序按照时间线从上往下执行):
在这里插入图片描述
这里只是简单画了六种,由于线程的调度是无序的所以这里会有无数种情况,但是在这无数种情况中,只有当两个线程的调度每次都满足前两种情况才不会发生BUG。

引发线程安全的原因

一般引发线程安全都有以下原因:

  1. 操作系统中线程的调度是随机的(抢占式执行,罪魁祸首)
  2. 多个线程针对同一个变量进行修改
  3. 修改操作不是原子的
  4. 内存可见性问题
  5. 指令重排序问题

想要解决线程安全问题就需要从上面这几点出发,由于我们上述的代码不涉及4和5所以无需考虑它们,而第一点是系统原因是客观存在的无法更改。

我们此时有两种解决方法:

  • 将这个代码改为单线程(解决多个线程针对同一个变量进行修改的问题);
  • 让该自增操作变为原子的(解决修改操作不是原子的问题)

这两种方法都可以解决此代码的线程安全问题,第一种很好实现,那么我们该怎样让这个自增操作变为原子的呢?加锁!

synchronized 关键字

synchronized 关键字是JAVA提供的一种常用的加锁工具。

注:

  • synchronized关键字在使用时需要搭配()和{};
  • 程序执行进入 { 加锁 离开 } 解锁 ,{} 里面就是被加锁的代码块
  • ()里面用来表示一个加锁的对象(这个对象是啥不重要,它的主要功能就是用来区分多个线程是否在竞争同一个锁)

如果多个线程对同一个线程尝试进行加锁操作就会产生锁竞争(其中一个线程就会发生阻塞等待),如果是不同对象就不会产生锁竞争,仍然是并发执行。
我们先随便创建一个Object类型的对象,命名为lock,将count++放入{}中

private static int count;
public static void main(String[] args) throws InterruptedException {Object lock = new Object();Thread t1 = new Thread(()->{for (int i = 0; i < 10000; i++) {synchronized(lock) {count++;}}});Thread t2 = new Thread(()->{for (int i = 0; i < 10000; i++) {synchronized(lock) {count++;}}});t1.start();t2.start();t1.join();t2.join();System.out.println(count);
}

在这里插入图片描述
由于我们对count++加了锁所以线程t1和t2就会在执行过程中相互影响。
当t1线程在执行++操作时,如果t2线程也想执行++操作就会发生阻塞等待,当t1线程执行完++操作出了 } 后会解锁,此时 t2 才会继续向下执行。
在这里插入图片描述

此时这个程序的执行顺序就只会是这类正确的类型:
在这里插入图片描述

相关文章:

线程安全(JAVA)

线程安全对于我们编写多线程代码是非常重要的。 什么是线程安全&#xff1f; 在我们平时的代码中有些代码在单线程程序中可以正常执行&#xff0c;但如果同样的代码放在在多个线程中执行就会引发BUG&#xff0c;而这种现象我们一般称为 “线程安全问题” 或 “线程不安全”。…...

Lightroom Classic 2021 v10.4

Lightroom Classic 2021是一款一体化照片管理和编辑解决方案。 它面向专业人士和高端用户&#xff0c;支持各种不同相机的原始图像编辑&#xff0c;包括Canon、Apple、Casio、Contax、DxO、Epson等品牌。这样可以将原图像快速导入进行编辑&#xff0c;轻松满足不同用户的需求。…...

Java面试题03

1.Java容器都有哪些 Java提供了丰富的容器类&#xff0c;包括Collection接口的实现类&#xff08;如List、Set等&#xff09;和Map接口的实现类&#xff08;如HashMap、TreeMap等&#xff09;&#xff0c;它们分别用于存储不同类型的元素和键值对。 Java容器主要分为两种类型&a…...

【操作系统】测试二

文章目录 单选题判断题填空题 单选题 在操作系统中&#xff0c;进行资源分配、调度和管理的最小独立单位是&#xff08;&#xff09;。 【 正确答案: C】 A. 作业 B. 程序 C. 进程 D. 用户 进程在发出I/O请求后&#xff0c;可能导致下列哪种进程状态演变&#xff1f; 【 正确答…...

大厂面试题-索引有哪些缺点以及具体有哪些索引类型

第一个&#xff0c;索引的优缺点 优点&#xff1a; 1、合理的增加索引 &#xff0c;可以提高数据查询的效率 &#xff0c;减少查询时间 2、有一些特殊的索引 &#xff0c;可以保证数据的完整性 &#xff0c;比如唯一索引 缺点&#xff1a; 1、创建索引和维护索引需要消耗时间…...

Vue真实技术面试题解析【兄弟组件、vue-router、增量部署】

兄弟组件的传值方式&#xff0c;有两种方式&#xff0c;把你尽可能知道的告诉我 我的答案&#xff1a;使用父组件传值 和 状态管理传值 使用事件总线&#xff08;Event Bus&#xff09;&#xff1a;创建一个空的 Vue 实例作为事件总线&#xff0c;在其中定义事件和对应的处理函…...

响应式生活常识新闻博客资讯网站模板源码带后台

模板信息&#xff1a; 模板编号&#xff1a;30483 模板编码&#xff1a;UTF8 模板分类&#xff1a;博客、文章、资讯、其他 适合行业&#xff1a;博客类企业 模板介绍&#xff1a; 本模板自带eyoucms内核&#xff0c;无需再下载eyou系统&#xff0c;原创设计、手工书写DIVCSS&a…...

获取AAC音频的ADTS固定头部信息

文章目录 前言一、AAC音频中的ADTS二、解析ADTS信息1.标准文档中介绍2.解析3.采样率索引和值4.下载AAC标准文档 前言 调试嵌入式设备中播放aac音频的过程中&#xff0c;了解了aac音频格式&#xff0c;记录在此&#xff0c;防止遗忘。 一、AAC音频中的ADTS ADTS&#xff08;Audi…...

二分查找--C++实现

1. 简介 满足有序性&#xff0c;每次排除一半的可能性。 2. 实现 2.1 手写 int bin_search(vector<int> &arr,int v) {int hi arr.size() - 1;int lo 0;while ( lo < hi){int mid (lo hi) >> 1;if (arr[mid] < v)lo mid 1;elsehi mid - 1;}re…...

计算机毕设 基于机器学习的文本聚类 - 可用于舆情分析

文章目录 0 简介1 项目介绍1.1 提取文本特征1.2 聚类算法选择 2 代码实现2.1 中文文本预处理2.2 特征提取2.2.1 Tf-idf2.2.2 word2vec 2.3 聚类算法2.3.1 k-means 2.3.2 DBSCAN2.4 实现效果2.4.1 tf-idf k-means聚类结果2.4.2 word2vec k-means 聚类结果 最后 0 简介 今天学…...

uniApp获取当前位置经纬度

以下是使用uni.getLocation获取当前位置的示例代码&#xff1a; 调用uni.getLocation方法获取当前位置信息 uni.getLocation({type: wgs84, // 坐标类型&#xff0c;默认为wgs84&#xff0c;可选的值为gcj02和bd09llsuccess: res > {// 获取成功&#xff0c;经度和纬度在r…...

this.$message提示内容添加换行

0 效果 1 代码 let msgArr [只允许上传doc/docx/xls/xlsx/pdf/png/jpg/bmp/ppt/pptx/rar/zip格式文件,且单个文件大小不能超过20MB,已过滤无效的文件] let msg msgArr.join(<br/>) this.$message({dangerouslyUseHTMLString: true,message: msg,type: warning })...

“三大阶段稳定性测试”筑牢长安链信任基石

前言 随着长安链应用生态的不断丰富、面对的应用场景更加多元&#xff0c;稳定性测试在长安链测试流程中占到越来越重要的位置。本文将介绍长安链稳定性测试的发展历程及如何通过三大阶段稳定性测试应对不断出现的复杂的商业需求&#xff0c;筑牢长安链信任基石。 功能测试和…...

手把手教你如何扩展(破解)mybatisplus的sql生成 | 京东云技术团队

mybatisplus 的常用CRUD方法 众所周知&#xff0c;mybatisplus提供了强大的代码生成能力&#xff0c;他默认生成的常用的CRUD方法&#xff08;例如插入、更新、删除、查询等&#xff09;的定义&#xff0c;能够帮助我们节省很多体力劳动。 他的BaseMapper中定义了这些常用的C…...

Spring Data JPA 项目配置与QueryDSL集成

一、说明 Spring Data JPA通过Spring Initializer创建时勾选相关依赖即可引入&#xff0c;QueryDSL需要单独引入。Spring JPA针对QueryDSL有比较好的兼容性&#xff0c;可以实现优雅的SQL构建。 二、设置JPA默认配置&#xff08;yaml格式&#xff09; spring:jpa:hibernate:…...

UE5数字孪生制作-数据篇(二) - 数据处理

1.卫星图与DEM高度图坐标一致处理 https://www.bilibili.com/video/BV1op4y1V71r?p4&vd_source707ec8983cc32e6e065d5496a7f79ee6 坐标系的调整 如何使用临时图层&#xff0c;对其他数据层进行裁切 &#xff08;1&#xff09;创建临时图层 &#xff08;2&#xff09;在临…...

Java 设计模式——享元模式

目录 1.概述2.结构3.实现3.1.抽象享元3.2.具体享元3.3.享元工厂3.4.测试 4.优缺点5.使用场景6.JDK 源码解析——Integer 类 1.概述 &#xff08;1&#xff09;享元模式 (Flyweight Pattern) 是一种结构型设计模式&#xff0c;主要通过共享对象来减少系统中的对象数量&#xff…...

再扩国产化适配版图,长安链新增数据库兼容性认证

基础软件的自主可控影响着国家信息安全与产业技术发展是否受制于人。实现真正长期可持续的技术自主可控&#xff0c;需要再进一步的是让国产化信息系统生态更有”活性“&#xff0c;基础软件之间、基础软件与其他国产上层应用的互相兼容、互相促进&#xff0c;共同繁荣发展&…...

MES系统数据集成系统源码

MES系统数据集成系统源码 1 MES的生产计划管理综述 生产计划的管理在MES系统中是非常重要的。我们知道&#xff0c;一般的情况下&#xff0c;企业的生产计划是由上层管理系统ERP来完成&#xff0c;那么MES中的生产计划和ERP的生产计划的不同点在于&#xff1a; ERP的生产计划…...

关于道一云-七巧使用感悟

低代码&#xff0c;开发快速&#xff0c;缺点组件比较少但能满足大多数场景&#xff0c;如果需要的话得自己造&#xff0c;官方的技术群里面普遍问题响应就很快&#xff0c;技术文档这个会抽风&#xff0c;有些代码就改个筛选条件本地死活运行不了&#xff0c;去官网那里问他们…...

AI-调查研究-01-正念冥想有用吗?对健康的影响及科学指南

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; &#x1f680; AI篇持续更新中&#xff01;&#xff08;长期更新&#xff09; 目前2025年06月05日更新到&#xff1a; AI炼丹日志-28 - Aud…...

Ubuntu系统下交叉编译openssl

一、参考资料 OpenSSL&&libcurl库的交叉编译 - hesetone - 博客园 二、准备工作 1. 编译环境 宿主机&#xff1a;Ubuntu 20.04.6 LTSHost&#xff1a;ARM32位交叉编译器&#xff1a;arm-linux-gnueabihf-gcc-11.1.0 2. 设置交叉编译工具链 在交叉编译之前&#x…...

C++初阶-list的底层

目录 1.std::list实现的所有代码 2.list的简单介绍 2.1实现list的类 2.2_list_iterator的实现 2.2.1_list_iterator实现的原因和好处 2.2.2_list_iterator实现 2.3_list_node的实现 2.3.1. 避免递归的模板依赖 2.3.2. 内存布局一致性 2.3.3. 类型安全的替代方案 2.3.…...

Qt/C++开发监控GB28181系统/取流协议/同时支持udp/tcp被动/tcp主动

一、前言说明 在2011版本的gb28181协议中&#xff0c;拉取视频流只要求udp方式&#xff0c;从2016开始要求新增支持tcp被动和tcp主动两种方式&#xff0c;udp理论上会丢包的&#xff0c;所以实际使用过程可能会出现画面花屏的情况&#xff0c;而tcp肯定不丢包&#xff0c;起码…...

JavaScript 中的 ES|QL:利用 Apache Arrow 工具

作者&#xff1a;来自 Elastic Jeffrey Rengifo 学习如何将 ES|QL 与 JavaScript 的 Apache Arrow 客户端工具一起使用。 想获得 Elastic 认证吗&#xff1f;了解下一期 Elasticsearch Engineer 培训的时间吧&#xff01; Elasticsearch 拥有众多新功能&#xff0c;助你为自己…...

Qt Http Server模块功能及架构

Qt Http Server 是 Qt 6.0 中引入的一个新模块&#xff0c;它提供了一个轻量级的 HTTP 服务器实现&#xff0c;主要用于构建基于 HTTP 的应用程序和服务。 功能介绍&#xff1a; 主要功能 HTTP服务器功能&#xff1a; 支持 HTTP/1.1 协议 简单的请求/响应处理模型 支持 GET…...

Ascend NPU上适配Step-Audio模型

1 概述 1.1 简述 Step-Audio 是业界首个集语音理解与生成控制一体化的产品级开源实时语音对话系统&#xff0c;支持多语言对话&#xff08;如 中文&#xff0c;英文&#xff0c;日语&#xff09;&#xff0c;语音情感&#xff08;如 开心&#xff0c;悲伤&#xff09;&#x…...

Java多线程实现之Thread类深度解析

Java多线程实现之Thread类深度解析 一、多线程基础概念1.1 什么是线程1.2 多线程的优势1.3 Java多线程模型 二、Thread类的基本结构与构造函数2.1 Thread类的继承关系2.2 构造函数 三、创建和启动线程3.1 继承Thread类创建线程3.2 实现Runnable接口创建线程 四、Thread类的核心…...

腾讯云V3签名

想要接入腾讯云的Api&#xff0c;必然先按其文档计算出所要求的签名。 之前也调用过腾讯云的接口&#xff0c;但总是卡在签名这一步&#xff0c;最后放弃选择SDK&#xff0c;这次终于自己代码实现。 可能腾讯云翻新了接口文档&#xff0c;现在阅读起来&#xff0c;清晰了很多&…...

三分算法与DeepSeek辅助证明是单峰函数

前置 单峰函数有唯一的最大值&#xff0c;最大值左侧的数值严格单调递增&#xff0c;最大值右侧的数值严格单调递减。 单谷函数有唯一的最小值&#xff0c;最小值左侧的数值严格单调递减&#xff0c;最小值右侧的数值严格单调递增。 三分的本质 三分和二分一样都是通过不断缩…...