/**
* 类说明:演示Volatile的提供的可见性
*/
public class VolatileCase {
// 说明:当ready没有volatile修饰时,执行结果是PrintThread线程一直处于被挂起状态,子线程感知不到主线程中的变量
// 当ready被volatile修饰时,保证了ready的可见性,所以子线程感知到了主线程变量的值从而结束子线程,继续执行主线程
private static boolean ready;
// private volatile static boolean ready;
private static int number;
private static class PrintThread extends Thread {
@Override
public void run() {
System.out.println("PrintThread is running.......");
while (!ready) ;//无限循环
System.out.println("number = " + number);
}
}
public static void main(String[] args) {
new PrintThread().start();
SleepTools.second(1);
number = 51;
ready = true;
SleepTools.second(5);
System.out.println("main is ended!");
}
}
执行结果:
PrintThread is running.......
main is ended!
说明:PrintThread子线程未执行完被挂起,主线程执行完毕。这是因为子线程在执行时拿到的ready默认值是false,子线程感知不到下面语句对ready的重新赋值,所以一直在无限循环。
当用volatile修饰后:
private volatile static boolean ready;
再次执行:
PrintThread is running.......
number = 51
main is ended!
说明:子线程感知到主线程的变量ready变为了true,从而跳出循环,执行完成。这就是volatile关键字的作用---可见性。
volatile的缺点:它只保证可见性,不能保证在并发下的原子性。
什么是不能保证原子性?
就是多线程下,多个线程都可以对其修饰的变量或者对象进行修改,就像没有加synchronized一样,都可以进行修改。造成前后读到的值不一致。
volatule 适用场景:一写多读。就是一个线程在写,其他线程都是读取的情况。