The Singleton Pattern
The singleton pattern is one of the simplest design patterns in Java. This design pattern is considered a creational pattern, as this pattern provides one of the best ways to create an object.
Sometimes it’s important for some classes to have exactly one instance. There are many times when we only need one instance of an object and if we instantiate more than one we’ll run into all sorts of problems, like incorrect program behavior, overuse of resources, or inconsistent results. You may require only one object of a class, for example, when you are creating:
- the context of an application.
- a thread manageable pool.
- registry settings.
- a driver to connect to the input or output console.
- and much more.
More than one object of that type clearly will cause inconsistency to our code.
The singleton pattern ensures that a class has only one instance and provides a global point of access to it. Although a singleton is the simplest in terms of its class diagram, because there is only one single class, its implementation is a bit trickier.
Motivation
Sometimes it's important to have only one instance for a class. For example, in a system there should be only one window manager or only one print spooler. Usually, singletons are used for centralized management of internal or external resources and they provide a global point of access to themselves.
The singleton pattern involves only one class which is required to instantiate itself and to make sure it creates no more than one instance.
At the same time, it provides a global point of access to that instance. In this case, the same instance can be accessed from anywhere, making it impossible to directly invoke the constructor each time.
How to Create a Class Using the Singleton Pattern
While there are many ways to create such a class, we will take a look the methods that have worked for me in the past.
Let’s start with a simple way. What if we provide a global variable that makes an object accessible? For example:
As we know, there is only one copy of the static variables of a class; we can apply this. As far as the client code using this sc
static variable... it's fine. But, if the client uses a new operator there would be a new instance of this class. To stop the class from getting instantiated outside the class, let’s make the constructor of the class private.
Is this going to work? I believe so. By keeping the constructor private, no other class can instantiate this class. The only way to get the object of this class is by using the sc
static variable, which ensures only one object is there. But, as we know, providing direct access to a class member is not a good idea. We will provide a method through which the sc
variable will get access, but not directly.
So, this is our singleton class, which makes sure that only one object of the class gets created and, even if there are several requests, only the same instantiated object will be returned. The one problem with this approach is that the object will get created as soon as the class gets loaded into the JVM. If the object is never requested, there will be a useless object inside the memory. It’s always a good approach that an object should get created when it is required. So, we will create an object on the first call and then return the same object on successive calls.
In the getInstance()
method, we check if the static variable sc
is null, then instantiate the object and return it. So, on the first call when sc
would be null, the object gets created and on successive calls it will return the same object. This surely looks good, doesn’t it? But this code will fail in a multi-threaded environment. Imagine two threads concurrently accessing the class, thread t1 gives the first call to the getInstance()
method, it checks if the static variable sc
is null, and then gets interrupted. Another thread (t2) calls the getInstance()
method, successfully passes the if
check, and instantiates the object. Then, thread t1 gets awoken and it also creates the object.
At this time, we have two objects of this class. To avoid this, we will use the synchronized keyword with the getInstance()
method. In this way, we force every thread to wait its turn before it can enter the method. So, no two threads will enter the method at the same time. The synchronized comes with a price, it will decrease the performance, but if the call to the getInstance()
method isn’t causing a substantial overhead for your application, forget about it. The other workaround is to move to an eager instantiation approach as shown in the previous example.
But if you want to use synchronization, there is another technique known as "double-checked locking" to reduce the use of synchronization. With the double-checked locking, we first check to see if an instance is created and, if not, then we synchronize it. This way, we only synchronize the first time.
Apart from this, there are some other ways to break the singleton pattern.
- If the class is serializable.
- If it’s clonable.
- If can be broken by reflection.
- If the class is loaded by multiple class loaders.
The following example shows how you can protect your class from getting instantiated more than once.
- Implement the
readResolve()
andwriteReplace()
methods in your singleton class and return the same object through them. - You should also implement the
clone()
method and throw an exception so that the singleton cannot be cloned. - An "if condition" inside the constructor can prevent the singleton from getting instantiated more than once using reflection.
- To prevent the singleton from getting instantiated from different class loaders, you can implement the
getClass()
method. The abovegetClass()
method associates the classloader with the current thread; if that classloader is null, the method uses the same classloader that loaded the singleton class.
Although we can use all these techniques, there is an easier way of creating a singleton class. As of JDK 1.5, you can create a singleton class using enums. The enum constants are implicitly static and final and you cannot change their values once created.
You will get a compile-time error when you attempt to explicitly instantiate an enum object. As enum gets loaded statically, it is thread-safe. The clone method in enum is final, which ensures that enum constants never get cloned. Enum is inherently serializable, the serialization mechanism ensures that duplicate instances are never created as a result of deserialization. Instantiation using reflection is also prohibited. These things ensure that no instance of an enum exists beyond the one defined by the enum constants.
When to Use Singletons
- There must be exactly one instance of a class, and it must be accessible to clients from a well-known access point.
- The sole instance is extensible by subclassing and clients can use an extended instance without modifying their code.
Pros and Cons of Using Singletons
Pros
- You can be sure that a class has only a single instance.
- You gain a global access point to that instance.
- The singleton object is initialized only when it’s requested for the first time.
Cons
- Violates the Single Responsibility Principle. The pattern solves two problems at a time.
- The Singleton pattern can mask bad design, for instance, when the components of the program know too much about each other.
- The pattern requires special treatment in a multithreaded environment so that multiple threads won’t create a singleton object several times.
- It may be difficult to unit test the client code of the singleton because many test frameworks rely on inheritance when producing mock objects. Since the constructor of the singleton class is private and overriding static methods is impossible in most languages, you will need to think of a creative way to mock the singleton. Otherwise, just don’t write the tests or use the Singleton pattern.
Conclusion
In the above article, we have gone into detail about the singleton pattern and how to implement the singleton pattern along with a practical demonstration. Though the singleton pattern looks like a simple implementation, we should resist using it until and unless there is a strong requirement for it. You can blame the unpredictable nature of the results on the multi-threading environment. Though we can use enum in Java 5+, sometimes it's difficult to implement your logic in an enum or there might be legacy code before Java 5 you have to contend with.
相关推荐
单例模式是一种设计模式,旨在确保一个类只有一个实例,并提供全局访问点。在单例模式中,类的构造函数是私有的,防止外部直接创建对象,而是通过静态方法获取该类的唯一实例。单例模式的唯一性通常是在进程范围内,...
"设计模式单例模式和工厂模式综合应用"的主题聚焦于两种常用的设计模式:单例模式和工厂模式,并探讨它们如何协同工作来实现高效、灵活的代码结构。这个主题尤其适用于Java编程语言,因为Java的面向对象特性使得设计...
单例模式是软件设计模式中的一种经典模式,它保证了类只有一个实例存在,并提供一个全局访问点。在Java等面向对象编程语言中,单例模式常用于管理共享资源,如数据库连接池、线程池或者配置文件等。结合工厂模式,...
单例模式是软件设计模式中的一种经典模式,用于确保一个类只有一个实例,并提供一个全局访问点。在Java中,有多种实现单例模式的方法,每种都有其特点和适用场景。接下来,我们将深入探讨这些实现方式。 首先,我们...
在C++编程中,单例模式是一种常用的软件设计模式,它保证一个类只有一个实例,并提供一个全局访问点。线程安全的单例模式在多线程环境下尤其重要,因为不正确的实现可能导致多个线程创建多个实例,这违反了单例模式...
**设计模式——单例模式** 在软件工程中,设计模式是一种在特定场景下解决常见问题的标准方案,可以被复用并提升代码质量。单例模式是设计模式中的一种,它保证一个类只有一个实例,并提供一个全局访问点。这种模式...
单例模式是软件设计模式中的一种,它保证一个类只有一个实例,并提供一个全局访问点。在C#中,单例模式常用于管理共享资源或控制类的实例化过程,以提高性能、节约系统资源,特别是在整个应用程序生命周期内只需要一...
单例模式是软件设计模式中的一种经典模式,其主要目的是确保一个类只有一个实例,并提供一个全局访问点。这种模式在很多场景下非常有用,比如控制共享资源、管理配置对象等。下面将详细介绍七种常见的单例模式实现...
单例模式是软件设计模式中的一种,它的主要目的是确保一个类只有一个实例,并提供一个全局访问点。在Java或类似的面向对象编程语言中,单例模式常用于管理共享资源,如数据库连接池、线程池或者配置文件等。在这个...
在C++编程中,单例模式是一种常用的软件设计模式,它保证一个类只有一个实例,并提供一个全局访问点。在这个特定的场景中,我们讨论的是一个实现了单例模式的日志类,该类专为多线程环境设计,具备日志等级控制、...
首先向关注过我这个系列...这立刻让我想到了最常用也是最简单最容易理解的一个设计模式 单例模式 何为 单例模式 ? 故名思议 即 让 类 永远都只能有一个实例。 由于 示例代码 比较简单 我也加了注释,这里就不在赘述
单例模式是软件设计模式中的一种,它的主要目的是确保一个类只有一个实例,并提供一个全局访问点。这种模式在很多场景下都非常有用,比如控制资源的唯一性、管理共享配置或者创建昂贵的对象时避免频繁创建销毁。 ...
Java中的单例模式是一种常用的软件设计模式,它保证一个类只有一个实例,并提供全局访问点。在Java编程中,单例模式常用于控制资源的访问,比如数据库连接池、线程池或者日志对象等。本篇文章将深入探讨如何在Java中...
单例模式是一种设计模式,它的主要目标是确保一个类只有一个实例,并提供一个全局访问点。在软件工程中,单例模式常用于控制资源的共享,比如数据库连接池、线程池或者日志系统等,这些资源通常需要全局唯一且高效地...
单例模式是软件设计模式中的一种,它的核心思想是确保一个类在整个系统中只有一个实例,并提供一个全局访问点。在Java或类似编程语言中,单例模式常常被用来管理资源,比如数据库连接、线程池或者配置信息,因为这些...
在Qt的Qml环境中,单例模式是一种设计模式,它允许在整个应用程序中创建一个全局访问点,确保某个类只有一个实例存在。这样的设计模式在需要共享数据或者服务时非常有用,避免了多处创建相同对象导致的数据不一致或...
单例模式是软件设计模式中的经典模式之一,其主要目的是控制类的实例化过程,确保在应用程序的整个生命周期中,某个类只有一个实例存在。这样的设计通常适用于那些需要频繁创建和销毁,但资源消耗较大的对象,如...
单例模式是一种常用的设计模式,它的核心思想是在整个应用程序中,一个类只能有一个实例存在。单例模式常用于控制资源的共享,例如数据库连接池、日志服务等。单例模式有多种实现方式,常见的包括懒汉式、饿汉式以及...
单例模式是软件设计模式中的一种,它保证一个类只有一个实例,并提供一个全局访问点。在C++中,实现单例模式有多种方法,我们将会深入探讨这一模式的原理、优缺点以及如何在实际编程中应用。 单例模式的核心在于...