登录
/
注册
首页
论坛
其它
首页
科技
业界
安全
程序
广播
Follow
关于
每日签到
每天签到奖励2圆-6圆
发帖说明
VIP申请
登录
/
注册
账号
自动登录
找回密码
密码
登录
立即注册
搜索
搜索
关闭
CSDN热搜
程序园
精品问答
技术交流
资源下载
本版
帖子
用户
软件
问答
教程
代码
写记录
写博客
VIP申请
VIP网盘
网盘
联系我们
每日签到
道具
勋章
任务
设置
我的收藏
退出
腾讯QQ
微信登录
返回列表
首页
›
业界区
›
业界
›
Java源码分析系列笔记-3.volatile
Java源码分析系列笔记-3.volatile
[ 复制链接 ]
臧莞然
2025-6-22 17:46:15
目录
1. 是什么
2. 什么情况 volatile 比 synchronized 更合适
2.1. 例子
2.2. 无法停止的原因分析
2.3. 解决方法
2.4. volatile vs synchronized
3. 汇编源码实验
3.1. 下载编译 hsdis-amd64.dll
3.2. 放入 JRE bin 目录下
3.3. 对比实验
3.4. 加上 jvm 参数运行
3.5. 输出结果对比
4. 根据实验结果分析原理
4.1. 可见性
4.2. 有序性
5. 参考
1. 是什么
Java 的轻量级锁,主要保证了有序性、可见性和一定的原子性
轻量级
相比于 synchronized,volatile 不会引起上下文切换(不会造成线程阻塞)
原子性
对任意单个 volatile 变量的读/写具有原子性,但类似于 volatile++这种复合操作不具有原子性
可见性
volatile 写会把数据同时写入主内存,并让其他线程对这个数据的工作内存失效,这样其他线程读的时候就需要去主内存中读取
有序性
对一个 volatile 变量的读,总是能看到(任意线程)对这个 volatile 变量最后的写入。
2. 什么情况 volatile 比 synchronized 更合适
2.1. 例子
如下程序。thread1 并不会停止
public class VolatileTest
{
private static boolean isRunning = true;
public static void main(String[] args) throws InterruptedException
{
Thread thread1 = new Thread(()->{
System.out.println("thread1 is running");
while (isRunning)
{
}
System.out.println("thread1 will be stopped");
});
thread1.start();
Thread.sleep(1000);
Thread thread2 = new Thread(()->{
System.out.println("thread2 is running");
isRunning = false;
System.out.println("thread2 change isRunning flag");
});
thread2.start();
thread1.join();
thread2.join();
}
}
复制代码
2.2. 无法停止的原因分析
Thread1 从主内存把 isRunning 这个变量加载到工作内存中,值为 true 所以一直运行
Thread2 从主内存把 isRunning 这个变量加载到工作内存中,值为 true 改为 false,写回工作内存,再写回主内存
Thread1 一直从工作内存中读取这个变量,一直为 true,所以还是无法停止运行
2.3. 解决方法
将 isRunning 使用 volatile 修饰
public class VolatileTest
{
private static volatile boolean isRunning = true;
public static void main(String[] args) throws InterruptedException
{
Thread thread1 = new Thread(()->{
System.out.println("thread1 is running");
while (isRunning)
{
}
System.out.println("thread1 will be stopped");
});
thread1.start();
Thread.sleep(1000);
Thread thread2 = new Thread(()->{
System.out.println("thread2 is running");
isRunning = false;
System.out.println("thread2 change isRunning flag");
});
thread2.start();
thread1.join();
thread2.join();
}
}
复制代码
2.4. volatile vs synchronized
volatilesynchronized内存模型三性可见性、有序性可见性、有序性、原子性是否造成线程阻塞【重量级别】不会会应用范围变量级别变量、方法、类级别
3. 汇编源码实验
3.1. 下载编译 hsdis-amd64.dll
参考How to build hsdis-amd64.dll and hsdis-i386.dll on Windows或者hsdis-amd64.7z
3.2. 放入 JRE bin 目录下
3.3. 对比实验
有 volatile
public class TestVolatile
{
private static volatile int i = 0;
public static void main(String[] args)
{
test();
}
private static void test()
{
i++;
}
}
复制代码
没有 volatile
public class TestVolatile
{
private static int i = 0;
public static void main(String[] args)
{
test();
}
private static void test()
{
i++;
}
}
复制代码
3.4. 加上 jvm 参数运行
-server -Xcomp -XX:+UnlockDiagnosticVMOptions -XX:-Inline -XX:CompileCommand=print,*TestVolatile.test
复制代码
使用 IDEA 的话如下图:
3.5. 输出结果对比
结果如附件:
volatile.txt
普通.txt
使用 BeyondCompare 对比图如下:
4. 根据实验结果分析原理
从汇编语言层面看,有 volatile 的结果比没有 volatile 的多了一个指令:lock addl $0x0,(%rsp) ,这条指令起到内存屏障的作用
禁止屏障两边的指令重排序
强制把写缓冲区/高速缓存中的脏数据等写回主内存,让缓存中相应的数据失效
4.1. 可见性
根据内存屏障的作用 2 可以实现可见性,表现如下
volatile 写会把数据同时写入主内存,并让其他线程对这个数据的工作内存失效
其他线程 volatile 读的时候就需要去主内存中读取
4.2. 有序性
根据内存屏障的作用 1 可以实现有序性,表现如下
在 volatile 写之前插入
释放屏障
【LoadStore+StoreStore】使得该屏障之前的任何读写操作都先于这个 volatile 写被提交;
在 volatile 读之后插入
获取屏障
【LoadLoad+LoadStore】使得这个 volatile 读操作先于该屏障之后的任何读写操作被提交。
5. 参考
深入理解 Java 内存模型(四)——volatile-InfoQ
再有人问你 volatile 是什么,把这篇文章也发给他。-HollisChuang's Blog
Java volatile 关键字底层实现原理解析 - 王泽远的博客 | Crow's Blog
精确解释 java 的 volatile 之可见性、原子性、有序性(通过汇编语言) - tantexian 的博客空间 - OSCHINA
volatile 与 synchronized 的区别 - 掘金
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
Java
源码
分析
系列
笔记
相关帖子
CMake构建学习笔记25-SpatiaLite库的构建
C#零基础入门系列(八)——数组
Java 8 终于要被淘汰了!带你速通 Java 8~24 新特性 | 又能跟面试官吹牛皮了
技术面:Java并发(线程池、ForkJoinPool)
无GC的Java创新设计思路:作用域引用式自动内存管理
解密prompt系列60. Agent实战:从0搭建Jupter数据分析智能体
社交app源码开发平台基础知识,软件二维码的生成
漏洞实战--java反序列化--用友NC UserAuthenticationServlet
技术面:Java并发(线程同步、死锁、多线程编排)
Tekla坐标定位插件源码
vip免费申请,1年只需15美金$
回复
使用道具
举报
提升卡
置顶卡
沉默卡
喧嚣卡
变色卡
千斤顶
照妖镜
相关推荐
业界
CMake构建学习笔记25-SpatiaLite库的构建
0
101
虽裘侪
2025-09-04
安全
C#零基础入门系列(八)——数组
0
87
祝安芙
2025-09-05
安全
Java 8 终于要被淘汰了!带你速通 Java 8~24 新特性 | 又能跟面试官吹牛皮了
0
730
任修
2025-09-05
业界
技术面:Java并发(线程池、ForkJoinPool)
0
146
揉幽递
2025-09-05
业界
无GC的Java创新设计思路:作用域引用式自动内存管理
0
863
昝梓菱
2025-09-05
业界
解密prompt系列60. Agent实战:从0搭建Jupter数据分析智能体
0
366
赊朗爆
2025-09-08
安全
社交app源码开发平台基础知识,软件二维码的生成
0
583
慷规扣
2025-09-09
安全
漏洞实战--java反序列化--用友NC UserAuthenticationServlet
0
646
锦惺
2025-09-09
业界
技术面:Java并发(线程同步、死锁、多线程编排)
0
967
丧血槌
2025-09-10
业界
Tekla坐标定位插件源码
0
251
慎气
2025-09-10
高级模式
B
Color
Image
Link
Quote
Code
Smilies
您需要登录后才可以回帖
登录
|
立即注册
回复
本版积分规则
回帖并转播
回帖后跳转到最后一页
签约作者
程序园优秀签约作者
发帖
臧莞然
2025-6-22 17:46:15
关注
0
粉丝关注
11
主题发布
板块介绍填写区域,请于后台编辑
财富榜{圆}
敖可
9984
杭环
9988
凶契帽
9988
4
氛疵
9988
5
黎瑞芝
9988
6
猷咎
9986
7
里豳朝
9986
8
肿圬后
9986
9
蝓俟佐
9984
10
虽裘侪
9984
查看更多