导致并发程序出现问题的根本原因是什么

并发程序出现问题的根本原因通常归结为两个核心问题:竞争条件(Race Condition)和内存可见性(Memory Visibility)。这些问题是由于多线程同时访问和修改共享资源而没有进行适当同步所导致的。现在让我们更详细地探讨这些问题。

竞争条件(Race Condition)

竞争条件发生在多个线程或进程在没有适当同步机制的情况下同时访问和修改共享数据。当多个线程访问和修改数据,最终结果依赖于线程执行的精确时序,这可能导致不一致和预期之外的结果。

示例代码
public class RaceConditionExample {private static int sharedVar = 0;public static void main(String[] args) throws InterruptedException {Thread incrementer = new Thread(() -> {for (int i = 0; i < 1_000; i++) {sharedVar++;}});Thread decrementer = new Thread(() -> {for (int i = 0; i < 1_000; i++) {sharedVar--;}});incrementer.start();decrementer.start();incrementer.join();decrementer.join();System.out.println("Final value: " + sharedVar);}
}

在没有适当同步的情况下运行这段代码可能会得到不同的输出结果,因为 sharedVar++sharedVar-- 都不是原子操作。实际上,每个操作可以分解为三个步骤:读取值、修改值、写回新值,线程在这些步骤之间的交替执行导致了不一致的结果。

内存可见性(Memory Visibility)

内存可见性问题发生在一个线程修改的共享变量的新值对于其他线程不可见。这是由于线程缓存导致的,线程可以在自己的本地内存(如 CPU 缓存)中保留共享变量的副本,而不是直接在主存中进行读写。

示例代码
public class VisibilityExample {private static boolean ready = false;private static int number;private static class ReaderThread extends Thread {public void run() {while (!ready) {Thread.yield();}System.out.println(number);}}public static void main(String[] args) {new ReaderThread().start();number = 42;ready = true;}
}

在这个例子中,没有适当的同步机制,没有办法保证主线程写入 readynumber 变量的值对启动的 ReaderThread 线程立即可见。因此,即使 ready 被设置为 trueReaderThread 线程也可能看不到这个改变,导致它无限循环。

解决方案

为了解决这些问题,我们需要使用同步机制,如 synchronized 关键字、ReentrantLockAtomic 变量类、volatile 关键字等,以确保操作的原子性和内存的可见性。

改进竞争条件示例
public class SynchronizedRaceConditionExample {private static int sharedVar = 0;private static synchronized void increment() {sharedVar++;}private static synchronized void decrement() {sharedVar--;}public static void main(String[] args) throws InterruptedException {Thread incrementer = new Thread(() -> {for (int i = 0; i < 1_000; i++) {increment();}});Thread decrementer = new Thread(() -> {for (int i = 0; i < 1_000; i++) {decrement();}});incrementer.start();decrementer.start();incrementer.join();decrementer.join();System.out.println("Final value: " + sharedVar);}
}
改进内存可见性示例
public class VolatileVisibilityExample {private static volatile boolean ready = false;private static int number;private static class ReaderThread extends Thread {public void run() {while (!ready) {Thread.yield();}System.out.println(number);}}public static void main(String[] args) {new ReaderThread().start();number = 42;ready = true;}
}

在这些改进的例子中,我们用 synchronized 关键字和 volatile 关键字提供了必要的同步机制。synchronized 保证了只有一个线程可以执行 incrementdecrement 方法,实现了原子性;而 volatile 保证了 ready 变量的改变对所有线程立即可见,解决了内存可见性问题。

这些同步技术可以有效地帮助避免并发程序中的问题,但使用它们也需要谨慎,因为不当的使用可能会导致死锁等其他并发问题,或者因过度同步导致性能问题。

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

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

相关文章

学习SSM的记录(八)-- SSM整合项目《任务列表案例》

前端程序搭建和运行 项目预览 接口分析 1.学习计划分页查询 需求&#xff1a;查询对应数据页数据 uri&#xff1a;schedule/{pageSize}/{currentPage} 请求方式&#xff1a;get 响应数据&#xff1a;json {"code":200,"flag":true,"data"…

Lucene 分词 示例代码

import org.apache.lucene.analysis.tokenattributes.CharTermAttribute; import org.apache.lucene.analysis.TokenStream; import org

基于springboot实现数据资产管理系统项目【项目源码+论文说明】计算机毕业设计

基于springboot实现数据资产管理系统演示 摘要 固定资产管理系统主要是完成对系统用户管理、资产信息管理、资产变更管理、资产用途管理、资产类别管理和资产增减管理。因为利用本系统管理员可以直接录入信息&#xff0c;修改信息&#xff0c;删除信息&#xff0c;并且若在录入…

JAVA初阶数据结构链表(2)双向链表( +专栏数据结构练习是完整版)

1.双向链表的结构&#xff08;双向不带头不循环链表&#xff09; 需要注意的一点就是&#xff0c;在jdk中的链表就是双向链表 一个节点有三个域 val&#xff08;数值域&#xff09; next&#xff08;地址域&#xff09; prev&#xff08;前驱记录前一个节点的地址&#xff09…

力扣思路题:重复的子字符串

注意比较j与j-i是否相同 bool repeatedSubstringPattern(char* s) {int i;int nstrlen(s);bool flag;for(int i1;i<n/2;i){if(n%i0){flagtrue;}for(int ji;j<n;j){if(s[j]!s[j-i]){flagfalse;break;}}if(flagtrue){return true;}}return false; }

腾讯云服务器地域有啥区别?选哪个比较好?

腾讯云服务器地域怎么选择&#xff1f;不同地域之间有什么区别&#xff1f;腾讯云哪个地域好&#xff1f;地域选择遵循就近原则&#xff0c;访客距离地域越近网络延迟越低&#xff0c;速度越快。腾讯云百科txybk.com告诉大家关于地域的选择还有很多因素&#xff0c;地域节点选择…

Python中的区块链技术与应用

区块链技术是一个复杂的概念&#xff0c;涉及许多不同的方面&#xff0c;如加密算法、数据结构、网络协议等。在这里&#xff0c;我将提供一个简单的区块链实现示例&#xff0c;以帮助你理解其基本概念。请注意&#xff0c;这个示例是为了教学目的而简化的&#xff0c;并不适用…

Shell脚本启动程序失败

单独执行.sh文件正常&#xff0c;在crontab定时任务中配置执行失败 #!/bin/bash# 定时任务执行失败添加以下俩行 source /etc/profile source ~/.bash_profile# 替换为实际脚本逻辑... echo "abc"

新版minio依赖对putObject进行了修改

老版的 PutObjectArgs putObjectArgsnew PutObjectArgs(bucketName, file.getOriginalFilename(), file.getInputStream(), null, null, file.getContentType()); 新版的 minioClient.putObject(PutObjectArgs.builder().bucket(bucketName).object(file.getOriginalFilenam…

sql server 恢复数据库、恢复单表数据的方法

如果不小心把某个表的数据删了&#xff0c;可以用之前的备份文件对单表进行数据恢复。 1、新建一个数据库&#xff08;全新的数据库&#xff09;&#xff0c;记得路径&#xff0c;恢复的时候要用到&#xff0c;新建完不要对数据库做什么操作。 2、用需要恢复表的数据库的备份文…

数据对比与处理利器——Pandas 实战

Pandas作为数据处理利器&#xff0c;在数据对比与处理方面发挥着重要作用。下面我们将通过实战案例来展示Pandas的强大功能。 一、数据导入与清洗 首先&#xff0c;我们需要从数据源导入数据&#xff0c;并进行必要的清洗。Pandas支持多种数据格式&#xff0c;如CSV、Excel、…

SpringBoot项目串口通讯之jSerialComm

目录 1.pom坐标2.控制层3.接口4.实现类-通过串口向设备发数据5.监听设备通过串口返回数据6.创建响应结果类ResponseResult 1.pom坐标 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xml…

【青书学堂】2024年第一学期 程序设计基础(高起专) 作业

【青书学堂】2024年第一学期 程序设计基础(高起专) 作业 为了方便日后复习&#xff0c;青书学堂成人大专试题整理。 若有未整理的课程&#xff0c;请私信我补充&#xff0c;欢迎爱学习的同学们收藏点赞关注&#xff01;文章内容仅限学习使用&#xff01;&#xff01;&#xff0…

基于FPGA的OV7725摄像头的HDMI显示(含源码)

1、概述 本文FPGA通过SCCB接口初始化OV7725摄像头寄存器&#xff0c;然后采集OV7725的摄像头数据&#xff0c;使用DDR3对数据进行暂存&#xff0c;最后将数据输出到HDMI显示器上进行显示。 该工程对应系统框图如下所示&#xff0c;主要包含OV7725驱动及数据处理模块、DDR3读写控…

CSS概念及入门

CSS概念及入门 简介 CSS 的全称为&#xff1a;层叠样式表 ( Cascading Style Sheets ) 。 CSS 也是一种标记语言&#xff0c;用于给 HTML 结构设置样式&#xff0c;例如&#xff1a;文字大小、颜色、元素宽高等等。 主流的布局方式:divcss。 组成 选择器 用于选择页面中的…

springboot混用RedisTemplate(lettuce、jedis)和Redisson客户端

手打不易&#xff0c;如果转摘&#xff0c;请注明出处&#xff01; 注明原文&#xff1a;https://zhangxiaofan.blog.csdn.net/article/details/136679352 redis常用的三大客户端&#xff1a;lettuce、jedis、redisson 一般都是 lettuce redisson&#xff08;推荐&#xff0…

防御安全(IPSec实验)

目录 需求&#xff1a; pc1 ping通 pc2 ,使用IPSec VPN 拓扑图&#xff1a; ​编辑实验配置&#xff1a; 注意&#xff1a; 直接在路由器r1和r2分别配置即可&#xff0c;路由器r1和r2要写一条缺省指向ISP 实验配置截图如下&#xff1a; 2. r1​编辑 3. r3​编辑 3.r…

工业互联网的安全策略及发展趋势——青创智通

工业物联网解决方案-工业IOT-青创智通 随着科技的不断发展&#xff0c;工业互联网作为工业与互联网的结合体&#xff0c;正日益成为推动工业转型升级的重要力量。然而&#xff0c;伴随着工业互联网的广泛应用&#xff0c;其安全问题也日益凸显。本文将从工业互联网的安全性角度…

Node.js_会话控制

介绍 HTTP是一种无状态的协议,没有办法区分多次的请求是否来自同一客户端,无法区分用户身份,需要通过会话控制来解决该问题 会话控制技术 cookie: 按照域名分别保存,默认在关闭浏览器的时候数据消失,可以通过第三个参数设置有效期。运行流程:浏览器向服务器发送请求时…

Go——数组

Golang Array和以往认知的数组有很大的。 数组是同一种数据类型的固定长度的序列。数组定义&#xff1a;var a[len] int&#xff0c;比如&#xff1a;var a [5]int&#xff0c;数组长度必须是常量&#xff0c;且类型的组成部分。一旦定义&#xff0c;长度不能变。长度是数组类…