6

对单例模式使用双重检查锁定习语会更好吗?还是同步方法?

IE:

private static volatile ProcessManager singleton = null;

public static ProcessManager getInstance() throws Exception {

    if (singleton == null) {
       synchronized (MyClass.class) {
          if (singleton == null) {
               singleton = new ProcessManager();
         }
      }
   }
   return singleton;

}

或者

private static processManager singleton = null;

public synchronized static processManager getInsatnce() throws Exception {

   if(singleton == null) {
            singleton = new processManager();
    }

    return singleton
 }
4

5 回答 5

6

让 ClassLoader 为您完成这项工作:

    /*
     * This solution takes advantage of the Java memory model's guarantees about class initialization
     * to ensure thread safety. Each class can only be loaded once, and it will only be loaded when it
     * is needed. That means that the first time getInstance is called, mySingletonServiceLoader
     * will be loaded and instance will be created, and since this is controlled by ClassLoaders,
     * no additional synchronization is necessary.
     */
    public static DocumentService getInstance() {
        return mySingletonServiceLoader.INSTANCE;
    }

    private static class mySingletonServiceLoader {
         static DocumentService INSTANCE = new DocumentService();
    }
}
于 2013-03-20T14:54:27.177 回答
0

第一个选项是正确的双重检查锁定实现,但如果 ProcessManager 类中没有更多公共方法但 getInstance 那么你所需要的就是

public class ProcessManager {
  private static ProcessManager instance;
  static {
      instance = new ProcessManager();
  }

  private ProcessManager() {
  }

   public static ProcessManager getInstance() {
       return instance;
   }
}

该类将在第一次 ProcessManager.getInstance() 调用时加载和初始化

于 2013-03-20T15:10:26.207 回答
0

基本上,您的第二个选项不会增加额外的保证。

您更频繁地检查,但它们之间仍可能发生并发访问,因此,您正在减少两个实例发生的可能性,但不会消除它。

于 2013-03-20T14:53:16.667 回答
0

第一个选项。

可以创建单个实例的多个版本...

getInstance() 调用中检查实例是否为null,如果为空则立即构造,然后instance返回 。

它应该是线程安全的。

也参考这个

于 2013-03-20T15:00:32.580 回答
0

如果需要延迟加载,我会坚持仔细检查而不是同步方法。最后,问题在于volatile 与 synchronized

易失性,只是强制对易失性变量的所有访问(读取或写入)都发生在主内存中,有效地将易失性变量排除在 CPU 缓存之外。这对于一些只要求变量的可见性正确且访问顺序不重要的操作可能很重要。

一旦实例被初始化,同步块将不会被执行(但对于竞争条件)。唯一需要支付的并发成本是对 volatile 变量的单次读取。

请注意,在Effective Java Bloch 中说,在局部变量中加载 volatile 字段可以提高性能(我理解这是因为 volatile 读取较少)

 public static ProcessManager getInstance() throws Exception {
  ProcessManager result = singleton;
  if (result == null) {
     synchronized (MyClass.class) {
        result = singleton;
        if (result == null) {
           singleton = result = new ProcessManager();            
        }
  }
  return result;
}
于 2013-03-20T15:17:06.310 回答