Volatile 关键字提供的可见性
/*** 类说明:演示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 {@Overridepublic 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 适用场景:一写多读。就是一个线程在写,其他线程都是读取的情况。