Java Singleton类中的线程安全

Singleton is one of the most widely used creational design pattern to restrict the object created by applications. If you are using it in a multi-threaded environment, then the thread-safety of the singleton class is very important.

Singleton是使用最广泛的创建设计模式之一,用于限制应用程序创建的对象。 如果在多线程环境中使用它,那么单例类的线程安全性非常重要。

In real-world applications, resources like Database connections or Enterprise Information Systems (EIS) are limited and should be used wisely to avoid any resource crunch.

在实际的应用程序中,数据库连接或企业信息系统(EIS)等资源是有限的,应明智地使用以避免任何资源紧张。

To achieve this, we can implement a Singleton design pattern. We can create a wrapper class for the resource and limit the number of objects created at runtime to one.

为此,我们可以实现Singleton设计模式 。 我们可以为资源创建一个包装器类 ,并将运行时创建的对象数限制为一个。

Java中的线程安全单例 (Thread Safe Singleton in Java)

In general, we follow the below steps to create a singleton class:

通常,我们按照以下步骤创建单例类:

  1. Create the private constructor to avoid any new object creation with new operator.

    创建私有构造函数,以避免使用new运算符创建任何新对象。
  2. Declare a private static instance of the same class.

    声明同一类的私有静态实例。
  3. Provide a public static method that will return the singleton class instance variable. If the variable is not initialized then initialize it or else simply return the instance variable.

    提供一个公共静态方法,该方法将返回单例类实例变量。 如果未初始化变量,则将其初始化,否则只需返回实例变量。

Using the above steps I have created a singleton class that looks like below.

使用上述步骤,我创建了一个单例类,如下所示。

ASingleton.java

ASingleton.java

package com.journaldev.designpatterns;

public class ASingleton {

	private static ASingleton instance = null;

	private ASingleton() {
	}

	public static ASingleton getInstance() {
		if (instance == null) {
			instance = new ASingleton();
		}
		return instance;
	}

}

In the above code, the getInstance() method is not thread-safe.

在上面的代码中,getInstance()方法不是线程安全的。

Multiple threads can access it at the same time. For the first few threads when the instance variable is not initialized, multiple threads can enter the if loop and create multiple instances. It will break our singleton implementation.

多个线程可以同时访问它。 对于实例变量未初始化的前几个线程,多个线程可以进入if循环并创建多个实例。 它将破坏我们的单例实现。

如何在Singleton类中实现线程安全? (How to achieve thread-safety in Singleton Class?)

There are three ways through which we can achieve thread safety.

我们可以通过三种方法来实现线程安全。

  1. Create the instance variable at the time of class loading.

    在类加载时创建实例变量。
  2. Pros:

    优点

  • Thread safety without synchronization

    没有同步的线程安全
  • Easy to implement

    易于实施

Cons:

缺点

  • Early creation of resource that might not be used in the application.

    尽早创建可能不在应用程序中使用的资源。
  • The client application can’t pass any argument, so we can’t reuse it. For example, having a generic singleton class for database connection where client application supplies database server properties.

    客户端应用程序无法传递任何参数,因此我们无法重用它。 例如,在客户端应用程序提供数据库服务器属性的情况下,具有用于数据库连接的通用单例类。
  • Synchronize the getInstance() method.

    同步getInstance()方法
  • Pros:

    优点

    • Thread safety is guaranteed.

      线程安全得到保证。
    • Client application can pass parameters

      客户端应用程序可以传递参数
    • Lazy initialization achieved

      实现了延迟初始化

    Cons:

    缺点

    • Slow performance because of locking overhead.

      由于锁定开销而导致性能降低。
    • Unnecessary synchronization that is not required once the instance variable is initialized.

      实例变量初始化后就不需要进行不必要的同步。
  • Use synchronized block inside the if loop and volatile variable

    在if循环和volatile变量中使用同步块
  • Pros:

    优点

    • Thread safety is guaranteed

      线程安全得到保证
    • Client application can pass arguments

      客户端应用程序可以传递参数
    • Lazy initialization achieved

      实现了延迟初始化
    • Synchronization overhead is minimal and applicable only for first few threads when the variable is null.

      同步开销最小,并且仅在变量为null时才适用于前几个线程。

    Cons:

    缺点

    • Extra if condition

      如果条件额外

    Looking at all the three ways to achieve thread-safety, I think the third one is the best option. In that case, the modified class will look like this:

    从实现线程安全的所有三种方式来看,我认为第三种是最佳选择。 在这种情况下,修改后的类将如下所示:

    package com.journaldev.designpatterns;
    
    public class ASingleton {
    
    	private static volatile ASingleton instance;
    	private static Object mutex = new Object();
    
    	private ASingleton() {
    	}
    
    	public static ASingleton getInstance() {
    		ASingleton result = instance;
    		if (result == null) {
    			synchronized (mutex) {
    				result = instance;
    				if (result == null)
    					instance = result = new ASingleton();
    			}
    		}
    		return result;
    	}
    
    }

    The local variable result seems unnecessary. But, it’s there to improve the performance of our code. In cases where the instance is already initialized (most of the time), the volatile field is only accessed once (due to “return result;” instead of “return instance;”). This can improve the method’s overall performance by as much as 25 percent.

    局部变量result似乎不必要。 但是,它可以改善我们的代码的性能。 如果实例已经初始化(大多数情况下),则volatile字段仅被访问一次(由于“返回结果;”而不是“返回实例;”)。 这样可以将方法的整体性能提高多达25%。

    If you think there are better ways to achieve this or if the thread-safety is compromised in the above implementation, please comment and share it with all of us.

    如果您认为有更好的方法可以实现此目的,或者在上述实现中线程安全性受到损害,请发表评论并与我们所有人共享。

    奖金提示 (Bonus Tip)

    String is not a very good candidate to be used with synchronized keyword. It’s because they are stored in a string pool and we don’t want to lock a string that might be getting used by another piece of code. So I am using an Object variable. Learn more about synchronization and thread safety in java.

    字符串不是非常适合与synced关键字一起使用的候选对象。 这是因为它们存储在字符串池中 ,我们不想锁定可能被另一段代码使用的字符串。 所以我正在使用对象变量。 了解有关Java中的同步和线程安全性的更多信息。

    GitHub Repository. GitHub Repository中检出更多Java示例。

    翻译自: https://www.journaldev.com/171/thread-safety-in-java-singleton-classes

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值