线程安全在Java中实现单例模式的有效方法? [复制]

     2023-03-31     72

关键词:

【中文标题】线程安全在Java中实现单例模式的有效方法? [复制]【英文标题】:Thread Safe Efficient way to implement singleton pattern in Java? [duplicate] 【发布时间】:2011-05-27 19:42:06 【问题描述】:

可能重复:Efficient way to implement singleton pattern in Java

我正在阅读这个Best Singleton Implementation In Java,但它不是线程安全的。

根据维基:

if(singleton==null) synchronized(Singleton.class) // this is needed if two threads are waiting at the monitor at the // time when singleton was getting instantiated if(singleton==null) singleton= new Singleton();

但是 Find Bugs 实用程序在这方面给出了两个错误: 1.双重空检查。 2. 静态字段延迟初始化不正确。

什么是最好的方法,

是否正确:

synchronized (Singleton.class) 
if (singleton== null) 
singleton= new Singleton();


【问题讨论】:

这是上述问题的重复;有关详细信息,请参阅该问题。但我不确定这个问题是否有这些有用的链接,所以:About double-checked locking in Java 链接到 these two Java 5 更新。另请参阅 Wikipedia's article on double-checked locking。但对于您的问题的实际答案,请参阅上面链接的问题。 【参考方案1】:

制作延迟加载单例的最有效/最简单的方法就是

enum Singleton 
   INSTANCE

注意:不需要锁定,因为类加载是线程安全的。该类默认为final,不能通过反射调用构造函数。在使用实例或使用类之前,不会创建实例。如果您担心该类可能会被意外使用,您可以将单例包装在内部类中。

final class Singleton 
    private Singleton()  
    static class SingletonHolder 
        static final Singleton INSTANCE = new Singleton();
    
    public static Singleton getInstance() 
        return SingletonHolder.INSTANCE;
    

恕我直言,您必须非常偏执才能认为这是一个更好的解决方案。

【讨论】:

在您的第二个代码中,您没有使用enum,但您使用的是class,所以我很困惑如何使用它。我想做一个枚举来初始化一个类,下次每次调用那个对象。我该怎么做。你能详细举个例子吗 @Manish 在这种情况下,使用enum,就像我在第一个示例中所做的那样。 是的,没关系,但我怎样才能只初始化一个类并在下次使用enum 时使用该实例。那是我的困惑。我在哪里看到enum Singleton INSTANCE 这么多,但不知道如何调用和初始化对象 您可以在代码中的任何位置使用Singleton.INSTANCE。以线程安全的方式调用一次的用于初始化此实例的代码将位于 enum 的构造函数中 @PeterLawrey 你没有忘记你的代码 sn-p 中的私有构造函数 Singleton() 吗?【参考方案2】:

关于这个问题已经写了很多。是的,简单的双重检查锁定模式并不安全。但是您可以通过将静态实例声明为 volatile 来使其安全。新的 Java 内存模型规范在处理 volatile 时为编译器添加了一些代码重新排序限制,因此原来的风险已经消失。

反正我在创建实例时很少真正需要这种惰性,所以我通常只是在类加载时静态地创建它:

private static MyClass instance = new MyClass();

这是简短而清晰的。作为替代方案,如果你真的想让它变得懒惰,你可以利用类加载特性并这样做:

public class MyClass 
    private static class MyClassInit 
        public static final MyClass instance = new MyClass();
    

    public static MyClass getInstance() 
        return MyClassInit.instance; 
    
...

在您第一次调用 getInstance() 之前,不会加载嵌套类。

【讨论】:

【参考方案3】:

Efficient way to implement singleton pattern in Java 已接受答案中的第一个代码示例 线程安全的。 INSTANCE的创建由类加载器在第一次加载类时执行;它只执行一次,并且以线程安全的方式:

public final class Foo 

    private static final Foo INSTANCE = new Foo();

    private Foo() 
        if (INSTANCE != null) 
                throw new IllegalStateException("Already instantiated");
        
    

    public static Foo getInstance() 
        return INSTANCE;
    

(复制自What is an efficient way to implement a singleton pattern in Java?)

问题中的第二个代码示例是正确且线程安全的,但它会导致每次调用 getInstance() 时同步,从而影响性能。

【讨论】:

不保护私有构造函数是相当偏执的。我假设它避免使用反射创建另一个实例,还是停止内部类调用构造函数? 我正在讨论上一个问题的答案,所以我按原样复制了代码。我个人也会省略if (INSTANCE != null) 检查。 因此我认为是例外。 ;) 您好 Eli,从您的回答中我了解到 Foo 对象将只有一个副本。但是假设两个线程同时调用 getInstance() 函数。那么我相信会有一个比赛条件。如何避免这种情况。因此我们需要避免这种情况。请查看 [link]***.com/questions/15930633/… 以获得最终答案...

如何使用工厂构造函数在 Dart 中实现单例模式?

】如何使用工厂构造函数在Dart中实现单例模式?【英文标题】:HowtoimplementSingletonpatterninDartusingfactoryconstructors?【发布时间】:2019-05-2603:15:48【问题描述】:我正在尝试在数据库帮助程序类中实现单例模式,但是,我似乎无法理... 查看详情

如何在qt中实现单例模式

参考技术AQT的单例和其他都是一样的,都是把构造私有,提供访问的方法。声明public:staticdemo*instance();private:demo();staticdemo*m_p;定义demo*demo::m_p=0;demo*demo::instance()if(!m_p)m_p=newdemo;returnm_p; 查看详情

如何在 C# 中实现单例设计模式? [复制]

】如何在C#中实现单例设计模式?[复制]【英文标题】:HowtoimplementsingletondesignpatterninC#?[duplicate]【发布时间】:2014-06-2800:20:24【问题描述】:如何在C#中实现单例设计模式?谁能帮帮我?【问题讨论】:如果你真的需要,请参阅cs... 查看详情

我们是不是需要有持久性对象才能在 php 中实现单例模式

】我们是不是需要有持久性对象才能在php中实现单例模式【英文标题】:Doweneedtohavepersistantobjecttoacheivesingletonpatterninphp我们是否需要有持久性对象才能在php中实现单例模式【发布时间】:2013-02-2815:08:05【问题描述】:我在Singleton... 查看详情

在控制台应用程序 C# 中实现单例的最佳方法?

】在控制台应用程序C#中实现单例的最佳方法?【英文标题】:BestwaytoimplementsingletoninaconsoleapplicationC#?【发布时间】:2009-12-0412:24:26【问题描述】:我有一个基于服务器的控制台应用程序。我只想为特定服务器一次运行它的1个实... 查看详情

如何在 Swift 中实现单例类

】如何在Swift中实现单例类【英文标题】:HowtoImplementSingletonclassinSwift[duplicate]【发布时间】:2016-02-1822:01:56【问题描述】:我是swift编程新手,请告诉我如何使用代码在swift中实现单例类。在obj-c中我知道+(id)sharedManagerstaticMediaMode... 查看详情

在啥情况下我们需要在javascript中实现单例类[重复]

】在啥情况下我们需要在javascript中实现单例类[重复]【英文标题】:Inwhatsituationdoweneedtoimplementsingletonclassinjavsacript[duplicate]在什么情况下我们需要在javascript中实现单例类[重复]【发布时间】:2015-05-1415:53:14【问题描述】:在什么... 查看详情

设计模式:单例模式的三种创建方式及其各自的优缺点

...源上的限制,怎样选择适当的方案来实现单例,以解决多线程的问题。假设使用多个类载入器,可能导致单例失效产生多个实例。双重检查加锁不适用于1.4及更早版本号的java。方式1:packagesingleton;/***同步getInstance()方法:*有点... 查看详情

【kotlin】lazy的线程安全模式

...常量不会多次初始化。但对于Android开发,大部分都属于线程安全(在UI线程里),但lazy默认是线程安全的,会上锁(可以看Java字节码),这样会影响性能。因此需要单独设置LazyThreadSafetyMode(线程安全模式).SYNCHRONIZED同步:只... 查看详情

java设计模式——单例模式

...方式:1)饿汉式(静态常量)2)饿汉式(静态代码块)3)懒汉式(线程不安全)4)懒汉式(线程安全,同步方法)5)懒汉式(线程不安全,同步代码块)6)双重检查7)静态内部类8)枚举 2.1、饿 查看详情

在 Node JS 应用程序中实现单例 mongoDB DB 对象

】在NodeJS应用程序中实现单例mongoDBDB对象【英文标题】:ImplementingsingletonmongDBDBobjectinNodeJSapplication[duplicate]【发布时间】:2018-10-1816:56:59【问题描述】:目前正在使用express,socket.io的nodeJS后端开发,并使用MongoDB作为其数据库。我... 查看详情

线程安全的单例模式

1.全局变量的缺点:必须在程序一开始就创建好对象,如果程序在这次的执行过程中又一直没用到它,就非常耗费资源。 2. 经典的单例模式实现:Java代码publicclassSingleton{//用一个静态变量来记录Singleton类的唯一实例privates... 查看详情

Java - 单例

...间】:2015-07-1801:01:53【问题描述】:我有一些关于在Java中实现单例模式的问题。当我们使用克隆时,可能会有多个单例实例。有什么具体的方法可以预防吗?如果我们使用序列化和反序列化创建另一个单例实例会有什么影响?... 查看详情

单例模式

...个对象存在对象的实例化必须在类中实现一、懒汉模式(线程不安全)packagecom.kevin;//懒汉模式调用静态方法的时候实例化publicclassSingleton1{privateStringname="lazy";privateSingleton1(){}privatestaticSingleton1single=null;//静态工厂方法publicstat 查看详情

unity3d日常开发unity3d中实现单例模式详解(代码片段)

...工具类、实现类,方便脚本调用。下面,就在Unity中实现单例模式。二、实现单例模式2-1、如何实现单例模式首先,来看一下单例模式的UML图:实现流程:1、私有的构造函数,也就是用static静态字段。static... 查看详情

java多线程——单例模式

这篇博客介绍线程安全的应用——单例模式。单例模式 单例模式,是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例的特殊类。通过单例模式可以保证系统中,应用该模式的类一个类只有一个实例... 查看详情

5java单例模式(线程安全性)(代码片段)

...eton();returninstance;需要实例的时候创建,此方式没考虑线程安全性问题,在多个线程并发调用newInstance()方法,可能会导致创建多个实例 查看详情

线程安全的单例模式(代码片段)

... 双重检查锁与延迟初始化(懒汉式)    在Java多线程程序中,有时候需要采用延迟初始化来降低初始化类和创建对象的开销,在使用这些对象时才进行初始化。延迟初始化需要注意线程安全  问题,否则就容易出现问... 查看详情