volatile修饰全局变量,可以保证并发安全吗?
今天被人问到volatile能不能保证并发安全?
呵,这能难倒我?
上代码:
//电脑太好,100线程起步~
public class ThreadTest {
private static volatile int num = 0; public static void main(String[] args) throws InterruptedException {
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start(); new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start(); new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start(); new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start(); new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
num++;
System.out.println(num);
}
}).start(); Thread.sleep(500);
System.out.println(num);
}
}
输出结果:
9998
9998
分析:
100个线程对volatilei修饰的num++,会被编译成以下三步:
1.获取i的值;2.执行i+1;3.将结果赋值给i。
volatile只能保证可见性,并不能保证原子性。
结论:
volatile只能保证这3步在编译后指令不会被重新排序,并不能保证并发数据安全。建议搭配上synchronized或其他Lock锁使用。
volatile修饰全局变量,可以保证并发安全吗?的更多相关文章
- volatile修饰符
Volatile 修饰的成员变量在每次被线程访问时,都强制从共享内存中重新读取该成员变量的值.而且,当成员变量发生变化时,会强制线程将变化值回写到共享内存.这样在任何时刻,两个不同的线程总是看到某个成 ...
- Java 的 volatile 修饰符
volatile 修饰符,用于多线程同步 volatile 修饰的成员变量在每次被线程访问时,都强制从共享内存中重新读取该成员变量的值.而且,当成员变量发生变化时,会强制线程将变化值回写到共享内存.这 ...
- Java中volatile修饰符,不稳定标记的用法笔记
今天学java特性时,发现了volatile修饰符,这个修饰符修饰的变量告诉java编译器忽略优化机制,这样的优势是: java优化后,寄存器会缓存内存里的变量,另一个线程修改这个变量的内存时,不会同 ...
- java中Volatile修饰符的含义
在java语言中:为了获得最佳速度,同意线程保存共享成员变量的私有拷贝.并且仅仅当线程进入或者离开同步代码块时才与共享成员变量的原始值进行对照. volatilekeyword的作用就是提示vm:对于 ...
- Java volatile修饰字段
一.关键字volatile修饰字段: 使用特殊域变量(volatile)实现线程同步 volatile:不稳定的:反复无常的:易挥发的: 1.volatile关键字为域变量的访问提供了一种免锁机制, ...
- volatile 修饰符的有过什么实践?
一种实践是用 volatile 修饰 long 和 double 变量,使其能按原子类型来读写. double 和 long 都是 64 位宽,因此对这两种类型的读是分为两部分的,第一次 读取第一个 ...
- 三个线程,ABC 10次(volatile+synchronized(2 synchronized可以保证内存可见性,所以去掉status 的volatile修饰符)
package ThreadABC; public class MyThread extends Thread { public static int status = 0; @Override pu ...
- 关于STM32库中 __IO 修饰符(volatile修饰符,反复无常的意思)
STM32例子代码中会有像这样的代码 static __IO uint32_t TimingDelay; 这里边的__IO修饰符不好理解,单从字面可以看出是为IO相关,查其标准库可以得知这个__IO ...
- STM32库中 __IO 修饰符(volatile修饰符)
STM32例子代码中会有像这样的代码 static __IO uint32_t TimingDelay; 这里边的__IO修饰符不好理解,单从字面可以看出是为IO相关,查其标准库可以得知这个__IO原 ...
随机推荐
- 后端程序员之路 57、go json
go自带json处理库,位于encoding/json,里面的test很具参考意义,特别是example_test.go json - The Go Programming Languagehttps ...
- HoloWAN在连接路由器时应该选择WAN口还是LAN口,有什么区别?
HoloWAN在连接路由器时应该选择WAN口还是LAN口,有什么区别? 在解决问题前,需要连接到,路由器的WAN口和LAN口的作用不同. WAN口是对外的接口,连接广域网.当联网设备和路由器都开启了D ...
- 翻译:《实用的Python编程》03_03_Error_checking
目录 | 上一节 (3.2 深入函数) | 下一节 (3.4 模块) 3.3 错误检查 虽然前面已经介绍了异常,但本节补充一些有关错误检查和异常处理的其它细节. 程序是如何运行失败的 Python 不 ...
- kubernetes Pod亲和性
三种调度粘性,主要根据官方文档说明: NodeSelector(定向调度).NodeAffinity(Node亲和性).PodAffinity(Pod亲和性). 1. nodeSelecto ...
- LeetCode-重建二叉树(前序遍历+中序遍历)
重建二叉树 LeetCode-105 首次需要知道前序遍历和中序遍历的性质. 解题思路如下:首先使用前序比遍历找到根节点,然后使用中序遍历找到左右子树的范围,再分别对左右子树实施递归重建. 本题的难点 ...
- 免费报表工具 积木报表(JiMuReport)的安装
分享一b/s报表工具(服务),积木报表(JiMuReport),张代浩大佬出品. 官网:http://www.jimureport.com/ 离线版官方下载:https://github.com/zh ...
- python分离不同后缀名的文件
功能描述 根据文件后缀名处理文件,分别拷贝到对应的文件夹下 example >>> .jpg 后缀 和.mp4 后缀文件处理 代码实现 #!/usr/bin/env python # ...
- (数据科学学习手札111)geopandas 0.9.0重要新特性一览
本文示例文件已上传至我的Github仓库https://github.com/CNFeffery/DataScienceStudyNotes 1 简介 就在几天前,geopandas释放了其最新正式版 ...
- 最权威的html 标签属性大全
<p>---恢复内容开始---</p>1.html标签 <marquee>...</marquee>普通卷动 <marquee behavior= ...
- python-3-2
一 切片 1.切片是list取值的一种方式 列子: nums = ['a','b','c','d','e','f','h','g','k','l','kk','nn','ee'] 取b和c元素出来 p ...