Java 单例类中的线程安全

Singleton 是最广泛使用的创意设计模式之一,用于限制应用程序创建的对象。如果您在多线程环境中使用它,那么 singleton 类的线程安全性非常重要。在现实世界的应用中,数据库连接或企业信息系统(EIS)等资源有限,应该明智地使用以避免任何资源崩溃。为了实现这一点,我们可以实施 [Singleton 设计模式](/community/tutorials/java-singleton-design pattern-best-practices-examples)。

在 Java 中使用 Thread Safe Singleton

thread safe singleton in java In general, we follow the below steps to create a singleton class:

  1. 创建私有 constructor以避免使用新操作员创建任何新对象
  2. 声明具有相同类型的私有 static实例
  3. 提供一个返回 singleton 类实例变量的公共静态方法。

使用上面的步骤,我创建了一个单曲类,看起来像下面。

 1package com.journaldev.designpatterns;
 2
 3public class ASingleton {
 4
 5    private static ASingleton instance = null;
 6
 7    private ASingleton() {
 8    }
 9
10    public static ASingleton getInstance() {
11    	if (instance == null) {
12    		instance = new ASingleton();
13    	}
14    	return instance;
15    }
16
17}

在上面的代码中, getInstance() 方法不是线程安全的。 多个线程可以同时访问它. 对于最初的几个线程,当实例变量没有初始化时,多个线程可以进入 if 循环并创建多个实例。

如何在Singleton Class中实现线程安全?

有三种方法可以实现线条安全。

  1. ** 在类加载时创建实例变量.**

:

  • 无同步的线程安全
  • 易于实施

:

  • 可能不会在应用程序中使用的资源的早期创建
  • 客户端应用程序无法传递任何论点,所以我们无法重复使用它. 例如,有一个通用单一类的数据库连接,客户端应用程序提供数据库服务器属性
  1. ** 同步 getInstance() 方法 **.

:

  • 线程安全保证
  • 客户端应用程序可以通过参数
  • 实现了缓慢的初始化

:

  • 由于锁定过头导致的性能较慢
  • 一旦实例变量初始化后不需要的无需同步
  1. ** 使用 if 循环和波动变量中的同步区块**

:

  • 线程安全得到保证
  • 客户端应用程序可以传输参数
  • 实现了缓慢的初始化
  • 同步过头是最小的,只有当变量为 null 时,第一批线程才适用。

:

附加如果条件

考虑到实现线程安全的所有三种方法,我认为第三种是最好的选择,在这种情况下,修改后的类将看起来像这样:

 1package com.journaldev.designpatterns;
 2
 3public class ASingleton {
 4
 5    private static volatile ASingleton instance;
 6    private static Object mutex = new Object();
 7
 8    private ASingleton() {
 9    }
10
11    public static ASingleton getInstance() {
12    	ASingleton result = instance;
13    	if (result == null) {
14    		synchronized (mutex) {
15    			result = instance;
16    			if (result == null)
17    				instance = result = new ASingleton();
18    		}
19    	}
20    	return result;
21    }
22
23}

局部变量结果似乎是不必要的,但它是为了改善我们的代码的性能。在实例已经初始化的情况下(大多数情况下),波动字段只能访问一次(由于回归结果;而不是回归实例;)。

奖金类型

String不是一个非常好的候选人,可以用同步的关键字。 这是因为它们存储在一个 string pool中,我们不想锁定一个可能被另一个代码使用的字符串。 所以我正在使用一个 Object 变量。 了解更多关于同步和 java 中的线程安全

您可以从我们的 GitHub 存储库中查看更多 Java 示例。

Published At
Categories with 技术
comments powered by Disqus