首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >两个单例都实现了同样的多线程验证?

问两个单例都实现了同样的多线程验证?
EN

Stack Overflow用户
提问于 2015-07-16 13:50:57
回答 4查看 139关注 0票数 0

下面的代码片段中有两个Singleton的实现。它们是否都是在Java多线程环境中实现单例的正确方法?

如果是这样的话,这是否意味着第二种实现方式是完全无用的,并且当您想要实现单例时,只需使用枚举方式?。

我的独白写法是:

代码语言:javascript
复制
public enum Singleton {
  INSTANCE();
}

另一种编写Singleton (显式同步)的方法:

代码语言:javascript
复制
public class Singleton {

  private static Singleton instance = null;
  private Singleton() {}

  public static synchronized Singleton getInstance() {
    if (instanz == null) {
      instanz = new Singleton();
    }
    return instanz;
  }
EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2015-07-16 16:33:37

一些程序员讨论如何创建单个程序的原因是,他们希望支持延迟创建,但担心访问器方法的后续调用的性能。

因此,使用synchronized的类实现了延迟创建方面,但随后的调用可能会受到synchronized不必要的开销的影响。为了克服这种假想的开销,发明了臭名昭著的双重检查锁,这引发了更多关于这个“问题”的讨论,而这个问题实际上是完全不相关的:

如果要将惰性创建与单个实例结合起来,则只需使用:

代码语言:javascript
复制
public class Singleton {
    static final Singleton INSTANCE=new Singleton();
    private Singleton(){}
    public static Singleton getInstance() {
        return INSTANCE;
    }
}

整个构造是延迟的,因为类初始化不会在第一个线程调用getInstance()之前发生,并且它是线程安全的,因为JVM保证类初始化本身是线程安全的。这是最有效的解决方案,因为后续调用将只读取一个final字段,而不需要同步。

这正是使用

代码语言:javascript
复制
public enum Singleton {
  INSTANCE;
}

它可以避免像编译器那样声明private构造函数。这个字段是隐式的static final。一个不同之处是,字段本身是公开的,不需要访问器方法。

此外,enum支持系列化,本质上。存储常量时,不存储实例数据,只存储类型和常量名称。反序列化之后,将查找当前运行时实例。因此,如果您需要序列化支持,应该首选enum,否则没有太大的差别(使用enum保存一些类型)。

但

  • 在您的应用程序中,您每隔多长时间需要一个单例?(如果你说“经常”,你应该重新考虑你的软件设计)
  • 在您的应用程序中,单例访问器方法的性能经常相关吗?
  • 单个实例创建的懒惰是否经常重要?
  • 如果你曾经需要一个单身人士,你是否真的需要一个“铁硬”的保证对单身人士的财产?也就是说,如果有人用肮脏的反射技巧创造了第二个实例,那么可能出现的问题就是他的问题,不是吗?

简单地说,单例设计模式似乎被严重高估了,并且讨论了如何高效地实现它,甚至更多的…。

票数 2
EN

Stack Overflow用户

发布于 2015-07-16 14:07:31

你们俩看起来都很好。但是,对于创建Singleton,我将建议采用以下方法,即100%线程安全,没有同步问题,因为利用了Java的类加载机制.

注:扣动扳机的功劳是“詹姆斯”。

Lazy singleton:

与此类似,类提供程序只加载一次,因此只有一个Network类实例,没有两个线程可以在同一个JVM中创建2个实例,因为类不会加载两次。

优势:

  • 只有在需要时才会创建实例。
  • 在调用getInstance()时,不需要承担同步的成本,当存在具有同步的getInstance()时,就会发生这种情况。
  • 类中可以有其他静态方法,它们可以在不创建实例的情况下被调用,并且只有在需要实例方法调用时才创建实例。这是惰性singleton.public类网络{私有网络(){}私有静态类提供程序{静态最终网络实例=新网络();}公共静态网络getInstance() {返回Provider.INSTANCE;}/更多代码的一个很好的优势. }

急切的单身人士:

代码语言:javascript
复制
private static Network INSTANCE = null;

private Network(){
}

static {
    INSTANCE = new Network();
}

public static Network getInstance() {
    return INSTANCE;
}

最后,:您得到了正确的第二种方法,您指定的第二种方法实际上是最后一种选择,因为每次有两个线程试图获取单例实例时,它都必须承担同步的成本。

现在,它的游戏v/s懒惰的单身汉。我提供了几个关于为什么人们不喜欢ENUM的链接,以及基于类加载的ENUM单例、v/s惰性单例的可伸缩性。

这两种方法都会无缝地工作,因此它的选择问题,因此真正的答案是“这取决于!”

票数 2
EN

Stack Overflow用户

发布于 2015-07-16 13:54:00

两者都是线程安全的,但是第一个使用枚举,可以避免不必要的锁定,并且在大多数情况下都更可取。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/31456178

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档