为了更好的说明volatile可见性的使用场景,看下面的案例:
/**
* <p>
* cpu现在是多核的,那么各自之间会存在缓存不一致的问题。
* 以前的解决办法是:总线加锁,在第一个线程来的时候开始加锁,当这个线程执行完成后,进行
* 解锁后,第二个线程才可以进行读取值进行操作。这样的话,效率低下。
* <p>
* 现在的解决办法是:MESI缓存一致性协议,一个线程在修改值后,需要同步到主存。这个时候
* 其他的CPU通过嗅探机制达到数据失效,然后从主存读取数据。
* <p>
* 加入volatile关键字后,底层是加入了lock的前缀指令,这个指令就是触发缓存一致性协议,对回写到
* 主存的数据进行加锁。
*
* </p>
*/
public class MyTest {
private static boolean flag = false;
public void refresh() {
String name = Thread.currentThread().getName();
flag = true;
System.out.println("线程" + name + "将数据进行了更改");
}
public void read() {
String name = Thread.currentThread().getName();
while (!flag) {
}
System.out.println("线程" + name + "将数据进行了更改");
}
public static void main(String[] args) {
MyTest myTest = new MyTest();
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
myTest.read();
}
});
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
myTest.refresh();
}
});
thread1.start();
try {
Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
}
thread2.start();
}
}
上述的结果为:
线程Thread-1将数据进行了更改
可以发现另外一个线程始终进行着死循环,无法退出,那么说明这个flag参数在另外一个线程中不可见,那么volatile上线了,可以在flag之前加一个volatile进行修饰,结果如下:
/**
* <p>
* cpu现在是多核的,那么各自之间会存在缓存不一致的问题。
* 以前的解决办法是:总线加锁,在第一个线程来的时候开始加锁,当这个线程执行完成后,进行
* 解锁后,第二个线程才可以进行读取值进行操作。这样的话,效率低下。
* <p>
* 现在的解决办法是:MESI缓存一致性协议,一个线程在修改值后,需要同步到主存。这个时候
* 其他的CPU通过嗅探机制达到数据失效,然后从主存读取数据。
* <p>
* 加入volatile关键字后,底层是加入了lock的前缀指令,这个指令就是触发缓存一致性协议,对回写到
* 主存的数据进行加锁。
*
* </p>
*/
public class MyTest {
private static boolean flag = false;
public void refresh() {
String name = Thread.currentThread().getName();
flag = true;
System.out.println("线程" + name + "将数据进行了更改");
}
public void read() {
String name = Thread.currentThread().getName();
while (!flag) {
}
System.out.println("线程" + name + "将数据进行了更改");
}
public static void main(String[] args) {
MyTest myTest = new MyTest();
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
myTest.read();
}
});
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
myTest.refresh();
}
});
thread1.start();
try {
Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
}
thread2.start();
}
}
结果为:
线程Thread-1将数据进行了更改
线程Thread-0将数据进行了更改