Out-of-order writes for Double-checked locking

前端 未结 4 1507
予麋鹿
予麋鹿 2021-02-06 15:44

In the examples mentioned for Out-of-order writes for double-checked locking scenarios (ref: IBM article & Wikipedia Article)

I could not understand the simple reaso

相关标签:
4条回答
  • 2021-02-06 16:25

    There's a general problem with code not being executed in the order it's written. In Java, a thread is only obligated to be consistent with itself. An instance created on one line with new has to be ready to go on the next. There's no such oblgation to other threads. For instance, if fieldA is 1 and 'fieldB' is 2 going into this code on thread 1:

    fieldA = 5;
    fieldB = 10;
    

    and thread 2 runs this code:

    int x = fieldA;
    int y = FieldB;
    

    x y values of 1 2, 5 2, and 5 10 are all to be expected, but 1 10--fieldB was set and/or picked up before fieldA--is perfectly legal, and likely, as well. So double-checked locking is a special case of a more general problem, and if you work with multiple threads you need to be aware of it, particularly if they all access the same fields.

    One simple solution from Java 1.5 that should be mentioned: fields marked volatile are guaranteed to be read from main memory immediately before being referenced and written immediately after. If fieldA and fieldB above were declared volatile, an x y value of 1 10 would not be possible. If instance is volatile, double-checked locking works. There's a cost to using volatile fields, but it's less than synchronizing, so the double-checked locking becomes a pretty good idea. It's an even better idea because it avoids having a bunch of threads waiting to synch while CPU cores are sitting idle.

    But you do want to understand this (if you can't be talked out of multithreading). On the one hand you need to avoid timing problems and on the other avoid bringing your program to a halt with all the threads waiting to get into synch blocks. And it's very difficult to understand.

    0 讨论(0)
  • 2021-02-06 16:26

    The constructor can have completed - but that doesn't mean that all the writes involved within that constructor have been made visible to other threads. The nasty situation is when the reference becomes visible to other threads (so they start using it) before the contents of the object become visible.

    You might find Bill Pugh's article on it helps shed a little light, too.

    Personally I just avoid double-checked locking like the plague, rather than trying to make it all work.

    0 讨论(0)
  • 2021-02-06 16:33

    Thread 2 checks to see if the instance is null when Thread 1 is at //3 .

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

    At this point the memory for instance has been allocated from the heap and the pointer to it is stored in the instance reference, so the "if statement" executed by Thread 2 returns "false". Note that because instance is not null when Thread2 checks it, thread 2 does not enter the synchronized block and instead returns a reference to a " fully constructed, but partially initialized, Singleton object."

    0 讨论(0)
  • 2021-02-06 16:43

    The code in question is here:

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

    Now the problem with this cannot be understood as long as you keep thinking that the code executes in the order it is written. Even if it does, there is the issue of cache synchronization across multiple processors (or cores) in a Symmetrical Multiprocessing architecture, which is the mainstream today.

    Thread1 could for example publish the instance reference to the main memory, but fail to publish any other data inside the Singleton object that was created. Thread2 will observe the object in an inconsistent state.

    As long as Thread2 doesn't enter the synchronized block, the cache synchronization doesn't have to happen, so Thread2 can go on indefinitely without ever observing the Singleton in a consistent state.

    0 讨论(0)
提交回复
热议问题