【问题标题】:Inner synchronization on the same object as the outer synchronization与外部同步在同一对象上的内部同步
【发布时间】:2010-03-17 15:15:11
【问题描述】:

最近我参加了一个关于一些设计模式的讲座:

已显示以下代码:

public static Singleton getInstance()
{
  if (instance == null)
  {
    synchronized(Singleton.class) {      //1
      Singleton inst = instance;         //2
      if (inst == null)
      {
        synchronized(Singleton.class) {  //3
          inst = new Singleton();        //4
        }
        instance = inst;                 //5
      }
    }
  }
  return instance;
}

取自:Double-checked locking: Take two

我的问题与上述模式无关,而是与同步块有关:

在第 1 行和第 3 行中完成的双重同步是否有任何好处,因为同步操作是在相同的对象上完成的

【问题讨论】:

    标签: java multithreading synchronization


    【解决方案1】:

    在旧的 Java 内存模型 (JMM) 中,退出 synchronized 块据称会将本地数据刷新到主内存。输入用于导致重新读取缓存数据的synchronized 块。 (这里,缓存包括具有相关编译器优化的寄存器。)旧的 JMM 已损坏且未正确实现。

    在新的 JMM 中,它什么也不做。新的 JMM 是为 1.5 指定的,并为“Sun”1.4 JRE 实现。 1.5 已在一段时间前结束了它的服务生命周期,因此您不必担心旧的 JMM(好吧,也许 Java ME 会做一些不可预测的事情)。

    【讨论】:

    • 好的...你能详细说明一下吗?我似乎仍然无法获得上述的用处。
    • AFAIK 同步仍然会进行一些刷新。 (见cs.umd.edu/~pugh/java/memoryModel/…
    • 哦,我才意识到你在谈论退出。错过了
    • @Jens 新的 JMM 倾向于通过一些刷新来实现,但它不是模型的一部分。嵌套锁定不会导致 happens-before 关系。
    • 很抱歉,我仍然有点困惑......但由于公众更喜欢这个答案,而且我可以确定当前 JMM 中的双重同步没有任何意义,我将接受这个答案。干杯
    【解决方案2】:

    我不是内存模型专家,但我认为必须考虑到“同步”不仅表示需要获取锁,而且还表示可能优化代码以及刷新和刷新缓存的规则。

    详情请见Java Memory Model

    【讨论】:

    • 新的 Java 内存模型不关心缓存的刷新。它使用了完全不同的 happens-before 关系。
    • 嗯,但为了确保这样的关系,必须进行兑现。或者至少我是这么认为的。你能指出我的资源,解释差异/关系吗?
    【解决方案3】:

    在同一个对象上同步两次确实会强制内部块内所做的所有更改在退出内部同步块时刷新共享内存。但是需要注意的重要一点是,没有规则说在内部同步块之后所做的更改不能在内部同步退出之前进行。

    例如

    public void doSomething()
    {
      synchronized(this) { // "this" locked
        methodCall1();
        synchronized(this) {
          methodCall2();
        } // memory flushed
        methodCall3();
      } // "this" unlocked and memory flushed
    }
    

    可以编译为按此顺序执行

    public void doSomething()
    {
      synchronized(this) { // "this" locked
        methodCall1();
        synchronized(this) {
          methodCall2();
          methodCall3();
        } // memory flushed
      } // "this" unlocked and memory flushed
    }
    

    如需更详细的说明,请查看 无法正常工作的修复程序部分中的 Double Check Locking 大约三分之一。

    【讨论】:

      猜你喜欢
      • 2015-08-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-02-14
      • 1970-01-01
      相关资源
      最近更新 更多