java单例模式_在Java中实现单例模式

单例模式保证只有一个带有全局访问点对象可以在给定的时间实例被创建。这是面向对象编程中最常用的技术之一。虽然它很简单,也许从类设计的角度来看最简单,但在尝试实现它们之前,必须先了解一些微妙的问题。本文将深入探讨这种模式,引用Java代码示例。

概观

在某种情况下,系统应该只允许一个类的一个对象在给定的时间点存在于内存中。这意味着,当程序实例化该对象时,不应该允许程序创建该类的其他对象。例如,在连接到数据库的系统中,仅使用一个对象来管理数据库连接。这可确保其他对象无法初始化不必要的连接,这会因多次实例化而松弛系统的整体性能。通过创建多个JDBC连接并观察性能,可以非常轻松地对此进行测试。表现肯定会受到影响或明显放缓。单例模式基本上保证系统只创建一个类的实例。

单例模式

使用单例模式是一种标准技术,可确保为给定类实例化一个且仅一个对象。它是Gang of Four讨论的二十四种设计模式之一。我们的想法是解决诸如实例化类的单个实例,访问类的唯一实例或控制类实例化过程等问题。实现此目标的关键技术是使用私有修饰符隐藏构造函数,并提供应用检查和验证的方法,以确保只创建该类的一个实例。

这很简单但有效地满足了需求。事实上,通过应用相同的原则,我们可以控制创建的类的实例数,而不仅限于单个实例。但是,这里我们只关注单个实例。

使用单例模式

不难发现我们实际上只需要内存中一个类的一个实例的情况。多个对象可能会破坏原因或对正在运行的应用程序的性能造成严重破坏。在面向对象的编程中,正在运行的应用程序通常在存储器中具有许多对象,在执行中交互并扮演关键部分。但是,当实现线程池,缓存,对话框或处理首选项和注册表设置的对象,数据库连接,日志记录,充当外围设备或图形卡的设备驱动程序的对象等都是我们想要的情况运行对象的单个实例; 否则,它会产生很多问题,如资源堵塞,内存过载和许多其他不一致的行为。

实现单例模式

这是模式的快速实现。

public final class Singleton { private static final Singleton singleInstance = new Singleton(); private Singleton(){ } public static Singleton getInstance(){ return singleInstance; }}public class TestSingleton { public static void main(String[] args){ Singleton s1; Singleton s2; s1 = Singleton.getInstance(); s2 = Singleton.getInstance(); if(s1 == s2){ System.out.println("References to same Singleton object"); } }}

singleton类被声明为final所以没有子类可以被创建。即使通过对此类进行子类化,这也会限制多个实例化。构造函数被声明为private; 因此,只有Singleton类可以使用此构造函数创建Singleton对象。对Singleton对象的静态引用调用私有构造函数,并仅传递该类的一个实例。在调用getInstance()方法时,仅接收对象的引用副本。

在这里,我们通过创建另一个名为TestSingleton的类来使用简单的测试。此类声明两个引用Singleton对象并调用getInstance()方法。然后,我们比较两个引用以确保它们实际引用相同的运行时实例而不是两个不同的对象。

有时,我们需要一个只在第一个静态方法被调用而不是之前创建实例的实现。在前面的示例中,对象是静态创建的; 在的getInstance()方法简单地返回引用中的作用。在这种情况下,我们希望在第一次调用时创建对象,称为延迟初始化。此外,我们希望调用是线程安全的 ; 否则,它可能导致奇怪的不稳定行为或内存泄漏,从而导致JVM崩溃。这是实现这一目标的例子。

public final class Singleton { private static volatile Singleton singleInstance = null; private Singleton(){ } public static Singleton getInstance(){ if (singleInstance == null) { synchronized(Singleton.class) { if (singleInstance == null) { singleInstance = new Singleton(); } } } return singleInstance; }}public class TestSingleton { public static void main(String[] args){ Singleton s1; Singleton s2; s1 = Singleton.getInstance(); s2 = Singleton.getInstance(); if(s1 == s2){ System.out.println("References to same Singleton object"); } }}

单例也可以使用Enum实现。实际上,在可能的情况下使用Enum通常更好,而不是使用类来实现单例模式。JVM保证只能从单例枚举创建一个实例。

public enum SingletonEnum { SINGLEINSTANCE; public void someMethod(){ // ... }}public class TestSingleton { public static void main(String[] args){ SingletonEnum s1; SingletonEnum s2; s1 = SingletonEnum.SINGLEINSTANCE; s2 = SingletonEnum.SINGLEINSTANCE; if (s1 == s2){ System.out.println("References to same Singleton object"); } }}

结论

一如既往,用户自行决定是良好设计的关键,因为不正确使用单例模式可能会导致其他问题; 如果它执行复杂和重量级的操作,则很难测试单例。更好的建议是使用依赖注入框架来构造单个对象。单例在诸如在GUI应用程序中创建对话框或者几乎没有机会拥有并发用户的情况下效果最佳。单例模式虽然有用,但却因在大型可伸缩应用程序中创建性能瓶颈而臭名昭着。

整理不易,请大家多多评论转发和关注,您的支持是我最大的动力。

96921fa33fa6dcf8578fadb9e34578dd.png
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值