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

________方块丶
  • 27

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

回复
阅读 1.2k
1 个回答
DDullahan
  • 65
✓ 已被采纳

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

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

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

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

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

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

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

宣传栏