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原 ...
随机推荐
- RabbitMQ-RPC版主机管理程序
一.作业需求 1.可以对指定机器异步的执行多个命令 例子: 请输入操作指令>>>:run ipconfig --host 127.0.0.0 in the call tack ...
- 剑指 Offer 41. 数据流中的中位数 + 堆 + 优先队列
剑指 Offer 41. 数据流中的中位数 Offer_41 题目详情 题解分析 本题使用大根堆和小根堆来解决这个寻找中位数和插入中位数的问题. 其实本题最直接的方法是先对数组进行排序,然后取中位数. ...
- PAT-1136(A Delayed Palindrome)字符串处理+字符串和数字间的转换
A Delayed Palindrome PAT-1136 我这里将数字转换为字符串使用的是stringstream字符串流 扩充:将字符串转换为数字可以使用stoi函数,函数头为cstdlib #i ...
- js和c#小数四舍五入
<script language="javascript"> document.write("<h1>JS保留两位小数例子</h1>& ...
- rest framework Views
基于类的意见 Django的基于类的意见是从旧式的观点颇受欢迎. - Reinout面包车里斯 REST框架提供了一个APIView类,它的子类Django的View类. APIView类是从正规不同 ...
- kubernetes生产实践之mysql
简介 kubedb mysql 生命周期及特性 Supported MySQL Features Features Availability Clustering ✓ Persistent Volum ...
- python报错:AttributeError: module 'pdb' has no attribute 'set_trace'
在第一次使用python中的pdb模块式,pdb.set_trace()时编译器总是会报错,一开始总是以为是自己的拼写错误,但经过反复检查后发现并不是自己的拼写错误.而是我创建的测试文件的名称是pdb ...
- ch2_8_1求解n阶螺旋矩阵问题
思路:循环输出,注意边界控制 import java.util.Scanner; public class ch2_8_1求解n阶螺旋矩阵问题 { public static void main(St ...
- windows 以管理员身份运行 代码
1 // 以管理员身份运行本进程 2 // 1 获取本进程的文件路径. 3 TCHAR path[MAX_PATH] = { 0 }; // 需要初始化 4 DWORD dwPathSize = MA ...
- ubuntu修改默认启动内核
一.序言 新换的笔记本由于太新的主板芯片,驱动还没有完善.每次升级系统内核都要小心谨慎.经常发生部分硬件驱动失败的事情.系统Ubuntu 20.04.2 LTS x86_64 ,我现在使用的两个版本的 ...