有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java在同步之前更新内存?

Java内存模型中提到:当线程退出同步块作为释放相关监视器的一部分时,JMM要求将本地处理器缓存刷新到主存。类似地,作为进入同步块时获取监视器的一部分,本地缓存将失效,以便后续读取将直接进入主内存,而不是本地缓存

那么,为什么在代码中我必须声明实例为volatile,因为当第二个线程进入同步块时,它将直接进入主内存

public final class MySingleton {
  private static MySingleton instance = null;
  private MySingleton() { } 
  public static MySingleton getInstance() {
    if (instance == null) {
      synchronized (MySingleton.class) {
        if (instance == null) {
          instance = new MySingleton();
        }
      }
    }
    return instance;
  }
}

我的意思是,当另一个线程进入同步块并进行第二次检查时,它应该像前面提到的那样从主内存更新


共 (2) 个答案

  1. # 1 楼答案

    必须将其声明为volatile,否则无法保证对getInstance()的两个调用将返回同一个实例

    不能保证主内存会被访问,只有缓存一致的值。i、 e.所有螺纹将看到相同的值

    顺便说一句:你当然知道它比需要的复杂得多。你所需要的只是

    public enum MySingleton {
         INSTANCE;
    }
    

    做了几乎相同的事情

  2. # 2 楼答案

    比赛条件如下:

    1. 线程A看到instance == NULL,正在运行此代码instance = new MySingleton();。对instance的写入可见,但对MySingleton的写入尚未可见

    2. 线程B看到instance != NULL并开始处理实例

    3. 线程B现在正在处理一个它看不到其结构的对象

    使instance易失性解决了这个问题,因为JDK内存规范(从JDK5开始)保证了对非易失性对象的写入不会与对易失性对象的写入顺序不一致。因此,任何看到instance != NULL的线程都必须看到实例本身