【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>>
volatile关键字不用多说,就是保证内存可见性,被它修饰的变量在被线程改变之后会马上同步回主内存(这句话实际有点问题,并不是会立马同步,而是在缓存行没空间或者遵循最晚时间原则),但是肯定能确保其他线程读到的是最新的值,这里直接上demo了(不BB那些没用的):
package unsafe;
/**
* @Authror ayo
* @Date 2019/12/25 14:39
*/
public class VolatileDemo {
/**
* 闹钟是否响铃(true代表响铃,false代表没响铃)
*/
private static boolean isClockRang = false;
public static void main(String[] args) throws InterruptedException {
new Thread(new Runnable() {
@Override
public void run() {
//如果闹铃不响我就一直睡觉
while (!isClockRang){
}
System.out.println("起床了");
}
}, "Thread1").start();
//休眠一秒钟,让线程1先跑起来
Thread.sleep(1000);
new Thread(new Runnable() {
@Override
public void run() {
isClockRang = true;
}
}, "Thread2").start();
//休眠一秒钟,让线程2把改变的值同步回主内存
Thread.sleep(1000);
System.out.println("闹钟是否响铃: " + isClockRang);
}
}
运行上面代码,得到如下结果:
都响铃了为什么不起床?很简单,没用volatile修饰嘛,加上试试(将isClockRang加上volatile修饰即可):
volatile起作用了,这没什么可研究的,但是我将代码稍微改点,volatile还去掉,另外打印一句话:
package unsafe;
/**
* @Authror ayo
* @Date 2019/12/25 14:39
*/
public class VolatileDemo {
/**
* 闹钟是否响铃(true代表响铃,false代表没响铃)
*/
private static boolean isClockRang = false;
public static void main(String[] args) throws InterruptedException {
new Thread(new Runnable() {
@Override
public void run() {
//如果闹铃不响我就一直睡觉
while (!isClockRang){
System.out.println("我不用volatile也行啊");
}
System.out.println("起床了");
}
}, "Thread1").start();
//休眠一秒钟,让线程1先跑起来
Thread.sleep(1000);
new Thread(new Runnable() {
@Override
public void run() {
isClockRang = true;
}
}, "Thread2").start();
//休眠一秒钟,让线程2把改变的值同步回主内存
Thread.sleep(1000);
System.out.println("闹钟是否响铃: " + isClockRang);
}
}
运行如下:
也可以啊,有疑问的按住ctrl点进System.out.println("我不用volatile也行啊")这句话中的println方法,你看见什么了?
public void println(String x) {
synchronized (this) {
print(x);
newLine();
}
}
这就是println的源码,很明显这个方法内部加了synchronized,加了synchronized意味着会有线程上下文切换,当线程1失去cpu使用权然后重启获取cpu使用权的时候,肯定要从主内存重新load变量isClockRang的嘛,原因就在这了。
来源:oschina
链接:https://my.oschina.net/ayo123/blog/3147370