代码之家  ›  专栏  ›  技术社区  ›  Sunny

Java中的双重检查锁定问题[duplicate]

  •  3
  • Sunny  · 技术社区  · 7 年前

    其中一篇文章提到了 "Double Check Locking"

    public class MyBrokenFactory {
      private static MyBrokenFactory instance;
      private int field1, field2 ...
    
      public static MyBrokenFactory getFactory() {
        // This is incorrect: don't do it!
        if (instance == null) {
          synchronized (MyBrokenFactory.class) {
            if (instance == null)
              instance = new MyBrokenFactory();
          }
        }
        return instance;
      }
    
      private MyBrokenFactory() {
        field1 = ...
        field2 = ...
      }
    }
    

    原因:- (请注意编号顺序)

    Thread 1: 'gets in first' and starts creating instance.
    
    1. Is instance null? Yes.
    2. Synchronize on class.
    3. Memory is allocated for instance.
    4. Pointer to memory saved into instance.
    
    [[Thread 2]]
    
    7. Values for field1 and field2 are written
    to memory allocated for object.
    
    .....................
    Thread 2: gets in just as Thread 1 has written the object reference
    to memory, but before it has written all the fields.
    
    5. Is instance null? No.
    6. instance is non-null, but field1 and field2 haven't yet been set!
       This thread sees invalid values for field1 and field2!
    

    问题:
    由于新实例(new MyBrokenFactory())的创建是从synchronized块完成的,那么在整个初始化完成之前(private MyBrokenFactory()完全执行)是否会释放锁?

    https://www.javamex.com/tutorials/double_checked_locking.shtml

    请解释一下。

    2 回复  |  直到 7 年前
        1
  •  0
  •   Community Mohan Dere    6 年前

    问题在于:

    实例是否为空?不。

    如果没有同步,线程2可能 看见 instance 作为 null 实例 synchronized 阻止:

    if (instance == null) {
      synchronized (MyBrokenFactory.class) {
    

    因为第一次检查完成了 街区外 不能保证线程2将看到正确的值 .

    field1 field2

    重新。您的编辑:

    因为新实例(new MyBrokenFactory())的创建是从synchronized块完成的

    我想你要问的是如果两个实例字段, 字段1 保证可见。答案是否定的,问题与 实例 在同步块中,不能保证这些实例字段将被正确读取。如果 实例 同步 块,因此不会发生同步。

        2
  •  0
  •   Pang Ajmal PraveeN    7 年前

    another similar question here .

    Synchronize保证只有一个线程可以输入一个代码块。但它不能保证在synchronized部分中所做的变量修改对其他线程是可见的。只有进入synchronized块的线程才能保证看到更改。这就是双重检查锁定被破坏的原因-它在读卡器端没有同步。读取线程可能会看到,singleton不为null,但singleton数据可能没有完全初始化(可见)。

    订购由 volatile 保证排序,例如write to volatile singleton static field保证对singleton对象的写入在write to volatile static field之前完成。它不阻止创建两个对象的单例,这是由synchronize提供的。

    类final静态字段不需要是可变的。在Java中 JVM 解决这个问题。