与外部同步在同一对象上的内部同步

时间:2010-03-17 15:15:11

标签: java multithreading synchronization

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

显示以下代码:

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

我的问题与上面提到的模式无关,但是使用了synchronized块:

对第1行和第1行中的双重同步有什么好处吗? 3关于同步操作是在相同的对象上完成的事实?

3 个答案:

答案 0 :(得分:11)

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

在新的JMM中它没有做任何事情。新JMM指定为1.5,并针对“Sun”1.4 JRE实现。 1.5前一段时间完成了它的服务终止期限,所以你不必担心旧的JMM(好吧,也许Java ME会做一些不可预测的事情)。

答案 1 :(得分:2)

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

您可以在Java Memory Model

中找到详细信息

答案 2 :(得分:2)

在同一对象上同步两次会强制执行内部块内所做的所有更改都是在退出内部同步块时刷新共享内存。但重要的是要注意的是,没有规则表明在退出内部同步之前无法在内部同步块之后进行更改。

例如

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部分约三分之一。