今天被人问到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修饰全局变量,可以保证并发安全吗?的更多相关文章

  1. volatile修饰符

    Volatile 修饰的成员变量在每次被线程访问时,都强制从共享内存中重新读取该成员变量的值.而且,当成员变量发生变化时,会强制线程将变化值回写到共享内存.这样在任何时刻,两个不同的线程总是看到某个成 ...

  2. Java 的 volatile 修饰符

    volatile 修饰符,用于多线程同步 volatile 修饰的成员变量在每次被线程访问时,都强制从共享内存中重新读取该成员变量的值.而且,当成员变量发生变化时,会强制线程将变化值回写到共享内存.这 ...

  3. Java中volatile修饰符,不稳定标记的用法笔记

    今天学java特性时,发现了volatile修饰符,这个修饰符修饰的变量告诉java编译器忽略优化机制,这样的优势是: java优化后,寄存器会缓存内存里的变量,另一个线程修改这个变量的内存时,不会同 ...

  4. java中Volatile修饰符的含义

    在java语言中:为了获得最佳速度,同意线程保存共享成员变量的私有拷贝.并且仅仅当线程进入或者离开同步代码块时才与共享成员变量的原始值进行对照. volatilekeyword的作用就是提示vm:对于 ...

  5. Java volatile修饰字段

     一.关键字volatile修饰字段: 使用特殊域变量(volatile)实现线程同步 volatile:不稳定的:反复无常的:易挥发的: 1.volatile关键字为域变量的访问提供了一种免锁机制, ...

  6. volatile 修饰符的有过什么实践?

    一种实践是用 volatile 修饰 long 和 double 变量,使其能按原子类型来读写. double 和 long 都是 64 位宽,因此对这两种类型的读是分为两部分的,第一次 读取第一个  ...

  7. 三个线程,ABC 10次(volatile+synchronized(2 synchronized可以保证内存可见性,所以去掉status 的volatile修饰符)

    package ThreadABC; public class MyThread extends Thread { public static int status = 0; @Override pu ...

  8. 关于STM32库中 __IO 修饰符(volatile修饰符,反复无常的意思)

    STM32例子代码中会有像这样的代码 static __IO uint32_t TimingDelay;  这里边的__IO修饰符不好理解,单从字面可以看出是为IO相关,查其标准库可以得知这个__IO ...

  9. STM32库中 __IO 修饰符(volatile修饰符)

    STM32例子代码中会有像这样的代码 static __IO uint32_t TimingDelay; 这里边的__IO修饰符不好理解,单从字面可以看出是为IO相关,查其标准库可以得知这个__IO原 ...

随机推荐

  1. C语言柔性数组和动态数组

    [前言]经常看到C语言里的两个数组,总结一下. 一.柔性数组 参考:https://www.cnblogs.com/veis/p/7073076.html #include<stdio.h> ...

  2. JPEG解码——(5)反量化和逆ZigZag变换

    本篇是该系列的第五篇,承接上篇huffman解码,介绍接下来的两个步骤--反量化和逆zigzag变换,即IDCT前的两个步骤. 需要说明的是,这两个步骤可以颠倒,本人的实现是,先反量化,再逆ZigZa ...

  3. java 集合 + 常见面试题

    1.1. 集合概述 1.1.1. Java 集合概览 从下图可以看出,在 Java 中除了以 Map 结尾的类之外, 其他类都实现了 Collection 接口. 并且,以 Map 结尾的类都实现了 ...

  4. C#中委托、匿名函数、Lambda表达式的一些个人理解

    0x01定义一个委托,相当于定义一个可以存储方法的特殊变量类型 下面我们看具体的代码,通过代码更好理解 delegate void IntMethodInvoker(int x); 这行代码就是声明一 ...

  5. Picgo + Gitee +Typora(自动上传)搭建markdown免费图库

    Picgo + Gitee +Typora(自动上传)搭建markdown免费图库 前言: ​ 在写博客的是时候,之前那都是直接在博客网站上面写好了,再一一插入图片,当要在同时2个以上的博客上面发表的 ...

  6. WPF 基础 - 点击事件的执行顺序及 Button 点击事件的特殊性

    1. 点击事件的执行顺序 PreviewMouseLeftButtonDown PreviewMouseDown MouseLeftButtonDown MouseDown PreviewMouseL ...

  7. LNMP配置——Nginx配置 —— 默认虚拟主机

    一.配置 首先修改配置文件 #vi /usr/local/nginx/conf/nginx.conf 在最后一个结束符号}前加一行配置: include vhost/*.conf; 意思就是/usr/ ...

  8. Distributed Cache(分布式缓存)-SqlServer

    分布式缓存是由多个应用服务器共享的缓存,通常作为外部服务存储在单个应用服务器上,常用的有SqlServer,Redis,NCache. 分布式缓存可以提高ASP.NET Core应用程序的性能和可伸缩 ...

  9. java IO NIO BIO 最权威的总结

    1. BIO (Blocking I/O) 1.1 传统 BIO 1.2 伪异步 IO 1.3 代码示例 1.4 总结 2. NIO (New I/O) 2.1 NIO 简介 2.2 NIO的特性/N ...

  10. 自导自演的面试现场之--你竟然不了解MySQL的组提交?

    Hi,大家好!我是白日梦!本文是MySQL专题的第 26 篇. 下文还是白日梦以自导自演的方式,围绕"组提交"展开本话题.看看你能抗到第几问吧 换一种写作风格,自导自演面试现场!感 ...