java中的单例模式。惰性初始化

发布于 2024-08-26 14:52:56 字数 487 浏览 3 评论 0原文

public static MySingleton getInstance() {
 if (_instance==null) {
   synchronized (MySingleton.class) {
      _instance = new MySingleton();
   }
 }
 return _instance;
} 

1.上面的getInstance方法的实现有缺陷吗? 2.两种实现有什么区别?

public static synchronized MySingleton getInstance() { 
 if (_instance==null) {
  _instance = new MySingleton();
 }

 return _instance;
} 

我在 stackoverflow 中看到了很多关于单例模式的答案,但我发布的问题是要了解在这种特殊情况下方法和块级别的“同步”的主要区别。

public static MySingleton getInstance() {
 if (_instance==null) {
   synchronized (MySingleton.class) {
      _instance = new MySingleton();
   }
 }
 return _instance;
} 

1.is there a flaw with the above implementation of the getInstance method?
2.What is the difference between the two implementations.?

public static synchronized MySingleton getInstance() { 
 if (_instance==null) {
  _instance = new MySingleton();
 }

 return _instance;
} 

I have seen a lot of answers on the singleton pattern in stackoverflow but the question I have posted is to know mainly difference of 'synchronize' at method and block level in this particular case.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

转瞬即逝 2024-09-02 14:52:56

1.上面的getInstance实现有缺陷吗
方法?

它不起作用。您最终可能会得到多个 Singleton 实例。

2.两种实现有什么区别?

第二个方法可以工作,但需要同步,当您从不同线程对该方法进行大量访问时,这可能会减慢系统速度。

最直接的正确实现:

public class MySingleton{
    private static final MySingleton _instance = new MySingleton();
    private MySingleton(){}
    public static MySingleton getInstance() { 
        return _instance;
    }
}

更短更好(安全地可序列化):

public enum MySingleton{
    INSTANCE;

    // methods go here
}

单例的延迟初始化是一个与实际实用性不成比例的主题(IMO 争论双重检查的复杂性)锁定(您的示例是第一步)只不过是一场小便竞赛)。

在 99% 的情况下,你根本不需要延迟初始化,或者 Java 的“类首次引用时初始化”就足够了。在剩下的 1% 的情况下,这是最好的解决方案:

public enum MySingleton{
    private MySingleton(){}
    private static class Holder {
         static final MySingleton instance = new MySingleton();
    }
    static MySingleton getInstance() { return Holder.instance; }
}

请参阅 Initialization-on-demand持有者习语

1.is there a flaw with the above implementation of the getInstance
method?

It does not work. You can end up with several instances of your Singleton.

2.What is the difference between the two implementations.?

The second one works, but requires synchronization, which could slow down the system when you have a lot of accesses to the method from different threads.

The most straightforward correct implementation:

public class MySingleton{
    private static final MySingleton _instance = new MySingleton();
    private MySingleton(){}
    public static MySingleton getInstance() { 
        return _instance;
    }
}

Shorter and better (safely serializable):

public enum MySingleton{
    INSTANCE;

    // methods go here
}

Lazy initialization of singletons is a topic that gets attention way out of proportion with its actual practical usefulness (IMO arguing about the intricacies of double-checked locking, to which your example is the first step, is nothing but a pissing contest).

In 99% of all cases, you don't need lazy initialization at all, or the "init when class is first referred" of Java is good enough. In the remaining 1% of cases, this is the best solution:

public enum MySingleton{
    private MySingleton(){}
    private static class Holder {
         static final MySingleton instance = new MySingleton();
    }
    static MySingleton getInstance() { return Holder.instance; }
}

See Initialization-on-demand holder idiom

空宴 2024-09-02 14:52:56

1.上面的getInstance实现有缺陷吗
方法?

是的,synchronized 关键字也应该包装 if 语句。如果不是,那么两个或更多线程可能会访问创建代码。

2.两种实现有什么区别?

第二种实现是正确的,并且从我的角度来看更容易理解。

在静态方法的方法级别使用synchronized 可在类上进行同步,即您在示例1 中所做的操作。在实例方法的方法级别使用synchronized 可在对象实例上进行同步。

1.is there a flaw with the above implementation of the getInstance
method?

Yes, the synchronized keyword should wrap the if statement as well. If it's not then two or more threads could potentially get through to the creation code.

2.What is the difference between the two implementations.?

The second implementation is correct and from my point of view easier to understand.

Using synchronized at the method level for a static method synchronizes on the class, i.e. what you've done in sample 1. Using synchronized at the method level for an instance method synchronizes on the object instance.

本王不退位尔等都是臣 2024-09-02 14:52:56

第一个有两个方面的缺陷。正如其他人在这里提到的,多个线程可以通过

if (_instance==null) {

它们会互相等待,直到对象完全构造完毕,但它们会进行实例化并替换变量中的引用。

第二个缺陷有点复杂。一个线程可以进入构造函数 new MySingleton(),然后 JVM 切换到另一个线程。另一个线程可能会检查该变量是否为 null,但该变量可能包含对部分构造的对象的引用。所以另一个线程在部分构造的 Singleton 上工作,这也不好。所以应该避免第一个变体。

第二种变体应该可以正常工作。不要太关心效率,除非你明确地将其识别为阻碍因素。现代 JVM 可以优化不需要的同步,因此在实际的生产代码中,这种构造可能永远不会损害性能。

The first is flawed in two ways. As others mentioned here, multiple threads could get through

if (_instance==null) {

They would wait for each other, until the object is completely constructed, but they would do the instantiation and replace the reference in the variable.

The second flaw is a little more complicated. One thread could get into the constructor new MySingleton() and then the JVM switches to another thread. Another thread may check the variable for null, but that may contain a reference to a partially constructed object. So the other thread works on the partially constructed Singleton, that's also not good. So the first variant should be avoided.

The second variant should work fine. Don't care too much about efficiency, until you identify this clearly as blocker. Modern JVMs can optimize away unneeded synchronizations, so in real production-code this construct may never hurt performance.

对岸观火 2024-09-02 14:52:56

Bob Lee 在中讨论了延迟加载单例的各种方法
延迟加载单例,“正确”的方法是按需初始化持有者 (IODH) 习惯用法 需要代码非常少,同步开销为零。

static class SingletonHolder {
  static Singleton instance = new Singleton();    
}

public static Singleton getInstance() {
  return SingletonHolder.instance;
}

Bob Lee 还解释了他何时想要延迟加载单例(在测试和开发期间)。老实说,我不相信有巨大的好处。

The various approaches to lazy-load singletons are discussed by Bob Lee in
Lazy Loading Singletons and the "right" approach is the Initialization on Demand Holder (IODH) idiom which requires very little code and has zero synchronization overhead.

static class SingletonHolder {
  static Singleton instance = new Singleton();    
}

public static Singleton getInstance() {
  return SingletonHolder.instance;
}

Bob Lee also explain when he wants to lazy load a singleton (during tests and development). Honestly, I'm not convinced there is a huge benefit.

尬尬 2024-09-02 14:52:56

第二个是线程安全的,但它在每次调用时都有同步的开销,无论实例是否被构造。第一个选项有一个主要缺陷,即它没有检查同步块中的 if (_instance == null) 以防止创建两个实例。

The second one is thread safe, but it has the overhead of synchronized on every call, no matter if the instance is constructed or not. The first option has one major flaw that it doesn't have a check for if (_instance == null) in the synchronized block to prevent creating two instances.

浮生未歇 2024-09-02 14:52:56

我建议以下实施

public class MySingleTon
{

  private static MySingleton obj;

  //private Constructor
  private MySingleTon()
  {
  }


  public static MySingleTon getInstance()
  {
     if(obj==null)
     {
        synchronized(MySingleTon.class)
        {
         if(obj == null)
         {
             obj = new MySingleTon();
         }
        }
     }
     return obj;    
  }
}

I would suggest the following implementation

public class MySingleTon
{

  private static MySingleton obj;

  //private Constructor
  private MySingleTon()
  {
  }


  public static MySingleTon getInstance()
  {
     if(obj==null)
     {
        synchronized(MySingleTon.class)
        {
         if(obj == null)
         {
             obj = new MySingleTon();
         }
        }
     }
     return obj;    
  }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文