Volatile
vloatile关键字是Java虚拟机提供的最轻量级的同步机制
,本文介绍volatile的作用和底层实现原理。
1、volatile解决线程安全性问题
我们说过,在多线程中存在竟态条件,会出现线程安全性问题
volatile关键字作用是保证可见性和有序性,并不会保证原子性。
volatile可以解决可见性问题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| class ThreadDemo1 implements Runnable{
public volatile boolean flag = false;
@Override public void run() { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); }
flag = true;
} }
public class safeVolatileDemo1 {
public static void main(String[] args) {
ThreadDemo1 threadDemo1 = new ThreadDemo1(); Thread thread = new Thread(threadDemo1); thread.start();
while(true){ if (threadDemo1.flag == true){ System.out.println("ThreadDemo1.flag = true");
break; } } } }
|
volatile解决重排序问题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| package com.jiang.ThreadSafe.safeVolatile;
public class safeVolatileDemo2 { private volatile static int x = 0, y = 0; private volatile static int i = 0, j = 0;
public static void main(String[] args) throws InterruptedException { int count = 0; while(true){ count++; x = 0; y = 0; i = 0; j = 0;
Thread one = new Thread(new Runnable() { @Override public void run() { i = 1; x = j; } }); Thread two = new Thread(new Runnable() { @Override public void run() { j = 1; y = i; } }); two.start(); one.start(); one.join(); two.join();
String result = "第" + count + "次(" + x + "," + y + ")"; if (x == 0 && y == 0) { System.out.println(result); break; } else { System.out.println(result); } } } }
|

2、volatile作用
在Happens-before先行发生原则中,有对volatile字段的描述
对某个volatile字段的写操作happens-before(先行于)每个后续对该volatile字段的读操作
对于一个线程对由volatile字段修饰的变量进行读操作时,直接读取主内存中的数据,进行写操作,直接写到主内存中。
使用volatile修饰字段之后:
修改的值会立即写回主存
修改值之后,其他线程中的工作内存的数据置为无效(在CPU缓存时提到,MESI会将数据设置为四种状态)
工作内存中数据无效,会直接读取主内存中的数据
3、volatile原理
加入volatile关键字时,所生成的汇编代码会多出一条lock前缀指令
这一条指令实际上相当于一个内存屏障(也称为内存栅栏),内存屏障会提供三个功能:
确保指令重排序时不会把其后面的指令排到内存屏障之前的位置,也不会把前面的指令排到内存屏障的后面。即在执行到内存屏障这句指令时,在它前面的操作已经全部完成
它会强制将对缓存的修改操作立即写入主存
如果是写操作,他会导致其他CPU中的对应的缓存行无效