高薪程序员必修课-volatile如何解决并发场景下可见性和有序性的问题

目录

前言

原理

可见性

有序性

示例

示例1:解决可见性问题

示例2:解决有序性问题

总结


前言

        在Java中,volatile 关键字用于解决并发场景下的可见性和有序性问题。通过理解 volatile 的工作原理和使用示例,可以更好地应用它来解决并发编程中的一些常见问题。

原理

可见性

在Java内存模型(JMM)中,每个线程都有自己的本地内存(缓存),线程对变量的读写操作先在本地内存中进行,然后再同步到主内存。这样,当一个线程修改了某个变量的值,其他线程可能无法立即看到这个变化,从而引发可见性问题。

volatile 关键字可以解决这个问题。当一个变量被声明为 volatile,它具有以下特性:

  • 可见性:对 volatile 变量的读写操作会直接操作主内存,而不是线程的本地内存。这意味着,当一个线程修改了 volatile 变量,其他线程立即可见。
有序性

在没有 volatile 的情况下,Java编译器、运行时和处理器可以对代码进行优化,重新排序指令。这可能会导致指令的执行顺序与代码的书写顺序不一致,从而引发有序性问题。

volatile 关键字通过内存屏障(Memory Barriers)确保了指令的有序性:

  • 写屏障:在写入 volatile 变量之前,会插入一个写屏障,确保在此之前的所有写操作都已写入主内存。
  • 读屏障:在读取 volatile 变量之后,会插入一个读屏障,确保在此之后的所有读操作都能从主内存读取最新的值。

示例

下面是一个示例,通过 volatile 关键字解决可见性和有序性问题:

示例1:解决可见性问题
public class VolatileVisibilityExample {private static volatile boolean running = true;public static void main(String[] args) {Thread worker = new Thread(() -> {while (running) {// Busy-wait loop}System.out.println("Worker thread stopped.");});worker.start();try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}running = false;System.out.println("Main thread set running to false.");}
}

在这个示例中,running 变量被声明为 volatile,确保当主线程将 running 设置为 false 后,工作线程能够立即看到这个变化并终止循环。

示例2:解决有序性问题
public class VolatileOrderingExample {private static volatile int x = 0;private static volatile int y = 0;public static void main(String[] args) {Thread writer = new Thread(() -> {x = 1; // Ay = 2; // B});Thread reader = new Thread(() -> {int r1 = y; // Cint r2 = x; // DSystem.out.println("r1: " + r1 + ", r2: " + r2);});writer.start();try {writer.join(); // 确保writer线程先执行完} catch (InterruptedException e) {e.printStackTrace();}reader.start();}
}

在这个示例中,xy 变量被声明为 volatile,确保写线程中的写操作(A和B)在读线程中的读操作(C和D)之前完成,从而保证有序性。在没有 volatile 的情况下,读线程可能会看到 y 已经被赋值为 2,而 x 仍然是初始值 0,导致输出不一致。

总结

  • 可见性volatile 确保变量的修改对所有线程立即可见。任何一个线程对 volatile 变量的修改都会立即写入主内存,并且其他线程对该变量的读取操作会直接从主内存读取最新的值。
  • 有序性volatile 通过内存屏障确保指令的有序执行。在对 volatile 变量的写操作前插入写屏障,确保写操作不会被重新排序;在对 volatile 变量的读操作后插入读屏障,确保读操作不会被重新排序。

通过使用 volatile 关键字,可以在多线程环境下确保变量的可见性和指令的有序性,从而避免竞态条件和内存可见性问题。然而,volatile 仅适用于某些特定场景,对于更复杂的同步问题,仍需使用其他同步机制,如 synchronizedLock 等。

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

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

相关文章

如何绕过验证码:终极指南 2024

你正在上网,突然出现了一个验证码,打断了你的浏览。是的,这就是那个确保你不是机器人的小测试,面对现实吧–它真的会拖慢你的进程。好消息是什么?你不必被卡住。你可以绕过验证码。所以,系好安全带&#xf…

Studying-代码随想录训练营day26| 491.递增子序列、46.全排列、47.全排列 II、51.N皇后、37.解数独、回溯总结

第26天,回溯part04,昨天休息复习总结回溯内容,💪(ง •_•)ง💪 目录 491.递增子序列 46.全排列 47.全排列 II 51.N皇后 37.解数独 回溯总结 491.递增子序列 文档讲解:代码随想录递增子序列 视频讲…

[数据库原理]数据库设计(er图)

xtu期末是机试,所以图形表示有点不同 实体之间的关系: 多对多:可以生成一个新的关系模型一对一:两边都要关联一对多、多对一 :一的主键可以作为多的外键 如有错误,欢迎指正!!&#x…

中画幅巡检相机-SHARE 100M A10

【毫厘之间,洞见非凡】 ——SHARE 100M A10中画幅测量相机,巡检行业的新选择 在巡检行业,精准度是关键,深圳赛尔智控科技有限公司最新推出的SHARE 100M A10中画幅测量相机,基于先进的IMX461影像传感器,拥有…

Java面试题:索引创建的原则

索引创建的原则 针对数据量较大,且查询较频繁的表建立索引 (单表超过10w) 针对于常作为 查询条件(where) 排序(order by) 分组(group by) 操作的字段建立索引 尽量选择区分度高的列作为索引,尽量选择唯一索引,区分度越高,使用索引的效率越高 字符串类型字段,字段长度越…

rmvb转mp4格式有什么好方法?这四种好方法轻松帮你完成转换!

rmvb转mp4格式有什么好方法?当大家深入探索视频格式的多元世界时,不禁会被各种格式的独特魅力所吸引,在众多选项中,RMVB和MP4无疑是两大热门选择,它们各自在不同的场合下展现出了令人瞩目的优势与局限,首先…

25考研:今年初试时间比去年更早了?

过去5年考研初试时间安排如下: 24考研:2023年12月23-24日(倒数第二个周末) 23考研:2022年12月24-25日(倒数第二个周末) 22考研:2021年12月25-26日(最后一个周末&#xf…

中英双语介绍美国的州:俄亥俄州(Ohio)

中文版 俄亥俄州简介 俄亥俄州位于美国中西部地区,是一个以其工业基础、文化遗产和教育资源而著称的州。以下是对俄亥俄州的详细介绍,包括其地理位置、人口、经济、教育、文化和主要城市。 地理位置 俄亥俄州北接密歇根州和伊利湖,东临宾…

【Linux】TCP协议【下二】{流量控制/滑动窗口/延迟应答/捎带应答/拥塞控制}

文章目录 1.流量控制--利用“窗口大小”字段协商数据量大小1. 1第一次的时候,怎么保证发送数据量是合理的1.2第三次握手ack的时候,可以携带数据!1.3流量控制,属于可靠性还是属于效率? 2.滑动窗口--利用滑动窗口解决批量…

x264 编码器分析、预测、估计模块相关结构体介绍

分析模块相关结构体 x264_mb_analysis_t 定义:在 analyse.c 文件中定义typedef struct {/* conduct the analysis using this lamda and QP */int i_lambda;int i_lambda2;int i_qp;uint16_t *p_cost_mv;uint16_t *p_cost_ref[2</

代码随想三刷动态规划篇6

代码随想三刷动态规划篇6 139. 单词拆分题目代码 多重背包题目代码 139. 单词拆分 题目 链接 代码 class Solution {public boolean wordBreak(String s, List<String> wordDict) {boolean[] dp new boolean[s.length()1];dp[0] true;for (int i 1; i < s.leng…

快速入门FreeRTOS心得(正点原子学习版)

对于FreeROTS&#xff0c;我第一反应想到的就是通信里的TDM&#xff08;时分多址&#xff09;。不同任务给予分配不同的时间间隔&#xff0c;也就是任务之间在每个timeslot都在来回切换。 这里有重要的一点&#xff0c;就是中断要短小&#xff0c;优先级是自高到底进行打断。 …

Cocos制作抖音小游戏接入侧边栏复访接口实例

本篇文章主要讲解&#xff0c;使用cocos接入抖音小游戏侧边栏接口的实例教程。 日期&#xff1a;2024年7月1日 作者&#xff1a;任聪聪 教程实例&#xff1a;https://download.csdn.net/download/hj960511/89509196 下载后可直接导入运行 上传游戏后抖音预审不通过 注意&#x…

98 - IDEA远程调试服务器Java程序

Java 提供了一套标准的调试协议&#xff08;JDWP - Java Debug Wire Protocol&#xff09;&#xff0c;允许调试器&#xff08;IDE&#xff09;与被调试程序&#xff08;应用&#xff09;之间进行通信。 1.服务器特定命令启动程序 在服务器上以以下命令启动Java程序 java -a…

南京林业大学点云相关团队论文

【1】Chen Dong, Wan Lincheng, Hu Fan, Li Jing, Chen Yanming, Shen Yueqian*, Peethambaran Jiju, 2024. Semantic-aware room-level indoor modeling from point clouds, International Journal of Applied Earth Observation and Geoinformation, 2024, 127, 103685. 语义…

【Android】【Binder】cpp 如何监听service死亡状态

前言 最近有个需求&#xff0c;需要在cpp bin中监听phone 进程异常死亡的状态。 代码 test.cpp #define LOG_TAG "BINDER_DEATH"#include <binder/IServiceManager.h> #include <binder/Binder.h> #include <binder/Parcel.h> #include <an…

人事系统不知道怎么选?这份国内外EHR系统对比收藏好了!(2000字干货)

随着信息化、数字化的发展&#xff0c;应用于企业运营的管理软件产品也越来越多。判断一个产品是否好用&#xff0c;首先应明确该产品是否能真正解决自身企业管理上的难点和痛点&#xff0c;人事系统产品理念从企业管理痛点中来&#xff0c;应用到服务企业管理中去&#xff0c;…

什么是脏读、幻读、不可重复读

数据库事务 数据库事务是指作为单个逻辑工作单元执行的一系列操作&#xff0c;这些操作要么全部成功执行&#xff0c;要么全部失败回滚&#xff0c;以保持数据库的一致性和完整性。在多线程或多用户同时操作时&#xff0c;难免会出现错乱与冲突&#xff0c;这就需要引入事务的…

软考高级-系统分析师知识点100条速记!

宝子们&#xff01;上半年软考已经结束一段时间了&#xff0c;准备备考下半年软考高级-系统分析师的小伙伴可以开始准备了&#xff0c;毕竟高级科目的难度可是不低的&#xff0c;相信参加过上半年系分的小伙伴深有体会。 这里给大家整理了100条系分知识点&#xff0c;涵盖全书9…

0050__重叠I/O模型

https://blog.51cto.com/u_11146845/6240720