证明 volatile 不具备原子性
假设一个简单场景:多个线程同时操作一个共享数据
public class AtomicTest {
public static volatile int count;
public static void main(String[] args) {
for (int i = 0; i < 500; i++) {
new Thread(()->{
AtomicTest.count++;
}).start();
}
/** 主线程等所有线程执行完,再去读取变量,3秒足够 */
ThreadUtils.threadSleep(3000);
System.out.println(AtomicTest.count);
}
}
多次运行后发现,结果基本都正确的理想值 500,因为每个线程运行的太快了。
但还是有可能会得到错误的值,放大这个可能性,修改:
// 让每个线程在操作数之前,都睡上10毫秒
ThreadUtils.threadSleep(10);
这样做的目的是,让多个线程都并行的效果
再运行,结构都是不同的错误值
其中,AtominTest.count++;
看起来只有一行代码,但它在字节码里可能需要多个指令来完成,在一个线程中的大致过程如下:
- 在方法去读取 count
- 压栈(每个线程都有它们独自的栈):把 count 压入栈顶
- 弹栈
- 加操作
- 把操作的结果值赋值给方法区的count
把这 5 个大致的操作看一个整体,当成原子性的操作,如果能保证多个线程遵循原子性的特性,那么结果是安全可靠的,
虽然volatile能保证 可见性 和 有序性,但它无法保证原子性,
每个线程都要执行上述的 5 个步骤,valatile 使得每个线程都在 主存中读写变量,并且按顺序执行操作步骤,但是多个线程一旦并行后,谁先做谁后做,就不能确定了
就是说,保证上述的原子性操作当前只有一个线程执行,完了后,再按序下一个线程来执行,synchronized
和 lock锁
不就是这么干的么🤔...
作者:Hong•Guo
出处:https://www.cnblogs.com/ghnb1/p/17326409.html
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix