Ensuring initialization methods complete before me

2019-08-31 08:50发布

问题:

Is there a way of ensure that a set of methods operating on a volatile static member variable via one thread will be done and over with before other threads access this member variable? I am trying something like this, but I am not sure if it would work.

public class MyClass
{
  private static final Object lock = new Object();
  public static volatile MyObj mo; //assume null will be checked before access

  public static void initialize()
  {
    if (mo == null)
    {
      synchronized(lock)
      {
        mo = new MyObj();
        mo.doInit();
        mo.doMoreInit();
      }
    }
  }
}

回答1:

You need to delay the assignment of mo until after all the methods are called (i.e. use a local variable and then assign mo as the last step).

Note, you are essentially implementing double checked locking (although using volatile makes it work "correctly"). you need to check mo for null again within the synchronized block.

also, there are some other (somewhat better) patterns for this like using the class initialization pattern for managing the synchronization. Pretty much every pattern imaginable is detailed here http://en.wikipedia.org/wiki/Singleton_pattern



回答2:

You're looking for the singleton pattern, using the double-checked locking idiom:

private static volatile MyObj obj = null;

public static MyObj getObj() {
    if (obj == null) {
        synchronized (MyClass.class) {
            if (obj == null) {
                obj = new MyObj();
            }
        }
    }
    return obj;
}

Note that the field is private, and accessed vie a getObj() method (and only through this method). If a field is public, any thread can access it whenever it wants to: you can't synchronize the access to a field without encapsulating its accesses behind methods.

There are easier ways to have this guarantee, but if you want lazy initialization, all of them, AFAIK, will require calling a method.



回答3:

You could set up a getter and have some flags which it checks to ensure that whatever methods are executed. The getter can either wait for the execution to finish to launch the required methods itself.