对于单例模式使用双重检查锁定习语是否最佳?

时间:2013-03-20 14:50:37

标签: java synchronization locking singleton

对于单身模式使用双重检查锁定习惯是否更好?还是同步方法?

即:

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
 }

5 个答案:

答案 0 :(得分: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();
    }
}

答案 1 :(得分:0)

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

您经常检查,但是它们之间仍然可以进行并发访问,因此,您正在减少发生两个实例的可能性,但不会消除它。

答案 2 :(得分:0)

第一个选项。

能够创建单个实例的多个版本......

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

它应该是线程安全的。

另请参阅this

答案 3 :(得分:0)

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

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

  private ProcessManager() {
  }

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

将在第一个ProcessManager.getInstance()调用

上加载和初始化该类

答案 4 :(得分:0)

如果需要延迟加载,我会坚持使用double-check而不是synchronized方法。最后,问题是volatile vs. synchronized的问题:

  

易失性,只是强制对主存储器发生对volatile变量的所有访问(读或写),从而有效地将volatile变量保留在CPU缓存之外。这对于某些只需要变量的可见性正确且访问顺序不重要的操作非常重要。

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

请注意,在 Effective Java Bloch中,在局部变量中加载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;
}