码迷,mamicode.com
首页 > 编程语言 > 详细

Java中Volatile关键字详解

时间:2019-09-01 13:02:36      阅读:123      评论:0      收藏:0      [点我收藏+]

标签:tail   ber   lan   ext   开头   一个   blog   throws   安全   

在原子性、可见性、有序性中,volatile关键字主要在可见性中发挥作用。

volatile声明的变量对所有线程来说是可见的,就是说当变量的值发生改变的时候,其他线程可以立马发现这个变化。

public class Main {
private static boolean isRuning;
private static int number;

private static class ReaderThread extends Thread {
public void run() {
while (!isRuning) {
System.out.println(number);
}
}
}

public static void main(String[] args) throws InterruptedException {
new ReaderThread().start();
Thread.sleep(1000);
number = 42;
isRuning = true;
Thread.sleep(1000);
}
}

  应该是由于编译器优化的存在,这里变量虽然没有被volatile修饰,但是仍然对其他线程可见。。。。。

 那为啥Volatile修饰的变量i++却会有并发问题呢?

因为i++并不是原子操作,

i++是有两步操作的,比如 i=0; i++

1.读取i=0

2.计算i+1,然后赋值给i

那么可能存在2个线程同时读取到i=0,并计算出结果i=1然后赋值给i
那么就得不到预期结果i=2。

就是说虽然Volatile修饰的变量的变化可以被其他线程看到,但是如果同时去读这个变量,然后进行写操作,则仍会导致线程安全问题。

当一个变量定义为 volatile 之后,将具备两种特性:

  1.保证此变量对所有的线程的可见性,这里的“可见性”,如本文开头所述,当一个线程修改了这个变量的值,volatile 保证了新值能立即同步到主内存,以及每次使用前立即从主内存刷新。但普通变量做不到这点,普通变量的值在线程间传递均需要通过主内存(详见:Java内存模型)来完成。

  2.禁止指令重排序优化。有volatile修饰的变量,赋值后多执行了一个“load addl $0x0, (%esp)”操作,这个操作相当于一个内存屏障(指令重排序时不能把后面的指令重排序到内存屏障之前的位置),只有一个CPU访问内存时,并不需要内存屏障;(什么是指令重排序:是指CPU采用了允许将多条指令不按程序规定的顺序分开发送给各相应电路单元处理)。

volatile 变量的内存可见性是基于内存屏障(Memory Barrier)实现。

内存屏障则由lock指令实现

参考:

https://blog.csdn.net/caoshangpa/article/details/78853919

https://www.jianshu.com/p/ccfe24b63d87

Java中Volatile关键字详解

标签:tail   ber   lan   ext   开头   一个   blog   throws   安全   

原文地址:https://www.cnblogs.com/akaneblog/p/11441863.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!