11

我有两个选择:

  1. 单例模式

    class Singleton{
        private static Singleton singleton = null;
    
        public static synchronized Singleton getInstance(){
            if(singleton  == null){
                singleton = new Singleton();
            }
            return singleton;
        }
    }
    
  2. 使用static final字段

    private static final Singleton singleton = new Singleton();
    
    public static Singleton getSingleton() {
        return singleton;
    }
    

有什么不同?(单线程或多线程)

更新:我知道 Bill Pugh 或enum方法。我不是在寻找正确的方法,但我只使用了 1。b/w 1 或 2 真的有什么区别吗?

4

4 回答 4

10

主要区别在于,使用第一个选项,单例只会在getInstance被调用时被初始化,而使用第二个选项,它会在包含类被加载后立即被初始化。

第三个(首选)惰性且线程安全的选项是使用枚举:

public enum Singleton {
    INSTANCE;
}
于 2012-12-05T13:23:01.697 回答
3

有一个区别:

解决方案1是延迟初始化,单例实例将在第一次调用时创建getInstance

解决方案 2 是急切初始化,单例实例将在类加载时创建

它们都是线程安全的,调用第二个多线程有点误导

于 2012-12-05T13:26:22.613 回答
2

第一种解决方案似乎更懒惰,但实际上并非如此。

当第一次访问静态方法/字段时初始化一个类。

这很可能getInstance()是该类唯一可公开访问的静态方法/字段。这就是单例的意义所在。

然后当有人getInstance()第一次调用时初始化该类。这意味着这两种解决方案在惰性方面基本相同。

当然,第二种解决方案看起来更好,性能更好。

于 2012-12-05T16:15:02.967 回答
1

因此,通过更新,上述两个选项都是线程安全的。但是,该synchronized选项要求调用instance的每个线程都获取此锁,因此如果这样做会降低性能。此外,synchronized在方法级别使用具有使用公共可用锁(类本身)的潜在问题,因此如果某个线程获取此锁(它可以),您最终可能会出现死锁。该static final选项性能更高,但不会对单例进行延迟初始化(取决于系统,这可能不是问题)。

另一个允许 Singleton 的线程安全惰性初始化的选项如下:

 public class MySingleton{
      private static class Builder{
          private static final MySingleton instance = new MySingleton();
      }

      public static MySingleton instance(){
           return Builder.intance;
      }
 }

这是因为静态内部类保证在包含类中的任何方法被执行之前被初始化。

于 2012-12-05T13:26:52.460 回答