如何使用双重检查锁定在Java中创建线程安全的单例?-问答-阿里云开发者社区-阿里云

开发者社区> 问答> 正文

如何使用双重检查锁定在Java中创建线程安全的单例?

2020-02-07 16:55:55 876 1

如何使用双重检查锁定在Java中创建线程安全的单例?

取消 提交回答
全部回答(1)
  • 珍宝珠
    2020-02-07 16:58:59

    在Java5之前的版本,使用双重检查锁定创建单例Singleton时,如果多个线程试图同时创建Singleton实例,则可能有多个Singleton实例被创建。从Java5开始,使用Enum创建线程安全的Singleton很容易。但如果面试官坚持双重检查锁定,那么你必须为他们编写代码。记得使用volatile变量。

    为什么枚举单例在Java中更好

    枚举单例是使用一个实例在Java中实现单例模式的新方法。虽然Java中的单例模式存在很长时间,但枚举单例是相对较新的概念,在引入Enum作为关键字和功能之后,从Java5开始在实践中。本文与之前关于Singleton的内容有些相关,其中讨论了有关Singleton模式的面试中的常见问题,以及10个Java枚举示例,其中我们看到了如何通用枚举可以。这篇文章是关于为什么我们应该使用Eeame作为Java中的单例,它比传统的单例方法相比有什么好处等等。

    Java枚举和单例模式

    Java中的枚举单例模式是使用枚举在Java中实现单例模式。单例模式在Java中早有应用,但使用枚举类型创建单例模式时间却不长.如果感兴趣,你可以了解下构建者设计模式和装饰器设计模式。

    1)枚举单例易于书写

    这是迄今为止最大的优势,如果你在Java5之前一直在编写单例,你知道,即使双检查锁定,你仍可以有多个实例。虽然这个问题通过Java内存模型的改进已经解决了,从Java5开始的volatile类型变量提供了保证,但是对于许多初学者来说,编写起来仍然很棘手。与同步双检查锁定相比,枚举单例实在是太简单了。如果你不相信,那就比较一下下面的传统双检查锁定单例和枚举单例的代码:

    在Java中使用枚举的单例

    这是我们通常声明枚举的单例的方式,它可能包含实例变量和实例方法,但为了简单起见,我没有使用任何实例方法,只是要注意,如果你使用的实例方法且该方法能改变对象的状态的话,则需要确保该方法的线程安全。默认情况下,创建枚举实例是线程安全的,但Enum上的任何其他方法是否线程安全都是程序员的责任。

    image.png

    你可以通过EasySingleton.INSTANCE来处理它,这比在单例上调用getInstance()方法容易得多。

    具有双检查锁定的单例示例

    下面的代码是单例模式中双重检查锁定的示例,此处的getInstance()方法检查两次,以查看INSTANCE是否为空,这就是为什么它被称为双检查锁定模式,请记住,双检查锁定是代理之前Java5,但Java5内存模型中易失变量的干扰,它应该工作完美。

    image.png

    你可以调用DoubleCheckedLockingSingleton.getInstance()来获取此单例类的访问权限。

    现在,只需查看创建延迟加载的线程安全的Singleton所需的代码量。使用枚举单例模式,你可以在一行中具有该模式,因为创建枚举实例是线程安全的,并且由JVM进行。

    人们可能会争辩说,有更好的方法来编写Singleton而不是双检查锁定方法,但每种方法都有自己的优点和缺点,就像我最喜欢在类加载时创建的静态字段Singleton,如下面所示,但请记住,这不是一个延迟加载单例:

    单例模式用静态工厂方法

    这是我最喜欢的在Java中影响Singleton模式的方法之一,因为Singleton实例是静态的,并且最后一个变量在类首次加载到内存时初始化,因此实例的创建本质上是线程安全的。

    image.png

    你可以调用Singleton.getSingleton()来获取此类的访问权限。

    2)枚举单例自行处理序列化

    传统单例的另一个问题是,一旦实现可序列化接口,它们就不再是Singleton,因为readObject()方法总是返回一个新实例,就像Java中的构造函数一样。通过使用readResolve()方法,通过在以下示例中替换Singeton来避免这种情况:

    image.png 如果Singleton类保持内部状态,这将变得更加复杂,因为你需要标记为transient(不被序列化),但使用枚举单例,序列化由JVM进行。

    3)创建枚举实例是线程安全的

    如第1点所述,因为Enum实例的创建在默认情况下是线程安全的,你无需担心是否要做双重检查锁定。

    总之,在保证序列化和线程安全的情况下,使用两行代码枚举单例模式是在Java5以后的世界中创建Singleton的最佳方式。你仍然可以使用其他流行的方法,如你觉得更好,欢迎讨论。

    0 0
相关问答

1

回答

Java单例模式的饿汉模式是线程安全吗?

2022-04-03 20:12:16 282浏览量 回答数 1

1

回答

java中String 类如何创建?

2021-11-15 13:12:28 80浏览量 回答数 1

1

回答

java中String 类如何使用?

2021-11-10 23:51:35 148浏览量 回答数 1

1

回答

Java的线程池应该如何创建?

2021-10-13 13:55:18 269浏览量 回答数 1

0

回答

【百问百答】Java开发手册灵魂15问之为什么禁止使用Executors创建线程池

2021-01-15 10:47:43 2153浏览量 回答数 0

1

回答

Java Executors工厂类怎么创建线程池?

2020-04-12 16:20:53 710浏览量 回答数 1

4

回答

Java中如何保证线程安全?

2019-11-11 14:28:55 3484浏览量 回答数 4

1

回答

在 Java 中你如何转储线程?如何分析它?

2019-10-28 14:37:01 188浏览量 回答数 1

1

回答

java 怎么检查线程

2018-05-10 20:07:23 1267浏览量 回答数 1

1

回答

基于Spring的JavaWeb项目,如何基于多线程进行改造?

2016-03-19 09:52:05 3581浏览量 回答数 1
+关注
7
文章
2309
问答
问答排行榜
最热
最新
相关电子书
更多
低代码开发师(初级)实战教程
立即下载
阿里巴巴DevOps 最佳实践手册
立即下载
冬季实战营第三期:MySQL数据库进阶实战
立即下载