我在学习java并发的是否发现了一个很诡异的事情,后来确定竟然是
System.out.println();
影响到了我的测试程序运行。
环境jdk1.8+idea2018
public static void main(String[] args) {
new Thread(()->{
while(flag){
//当我不加下面的这句话时,这个线程将一直循环,不会感知flag变化
//加了之后,线程可以感知flag的变化,及时退出
//System.out.println();
}
},"theadA").start();
try {
Thread.currentThread().sleep(2000);
} catch (Exception ex){
}
System.out.println("begin");
flag = false;
System.out.println("end");
}
感到十分蹊跷,后来发现println()->newLine()方法时加锁的,推测可能跟它有关!
引发思考,难道在线程内的任意位置使用synchronized关键字,都会让线程工作内存中所有缓存变量(即使那个变量并不在synchronized 代码块内)失效,重新去获取最新的变量吗?
并发程序具有线程安全的特点需要满足三个条件,原子性,可见性,有序性。
看题主的描述,应该已经知道了多线程下缓存一致性的问题,即可见性。
synchronized能够实现原子性和可见性以及有序性。
在Java内存模型中,synchronized规定,线程在加锁时,按序进行以下流程
因此在获取锁后,可保证共享变量反应的是内存中真实的值。
而
voliate
保证,在多线程环境下,线程修改voliate
修饰的变量会直接写入主存,从缓存中读取变量的其他线程会被通知缓存的变量值已经过期,会从主存中读取变量的值写入缓存。所以这里题主可以对flag加voliate修饰,可以看到对
flag = false;
的感知