java synchronized 是否具有这样的语义(或者是功能)

我在学习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 代码块内)失效,重新去获取最新的变量吗?

阅读 2.2k
1 个回答

并发程序具有线程安全的特点需要满足三个条件,原子性,可见性,有序性。

看题主的描述,应该已经知道了多线程下缓存一致性的问题,即可见性。

synchronized能够实现原子性和可见性以及有序性。
在Java内存模型中,synchronized规定,线程在加锁时,按序进行以下流程

  1. 清空工作内存
  2. 从主内存中拷贝最新变量的副本到工作内存
  3. 执行完代码
  4. 将更改后的共享变量的值刷新到主内存中
  5. 释放锁

因此在获取锁后,可保证共享变量反应的是内存中真实的值。

voliate保证,在多线程环境下,线程修改voliate修饰的变量会直接写入主存,从缓存中读取变量的其他线程会被通知缓存的变量值已经过期,会从主存中读取变量的值写入缓存。

所以这里题主可以对flag加voliate修饰,可以看到对flag = false;的感知

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题