0% found this document useful (0 votes)
13 views21 pages

Understanding the Singleton Pattern

Uploaded by

buseccoban
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
13 views21 pages

Understanding the Singleton Pattern

Uploaded by

buseccoban
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

CSE351 DESIGN PATTERNS

05. SINGLETON PATTERN

One of a Kind Objects


Developer: What use is that?
Guru: There are many objects we only need one of: thread pools, caches, dialog boxes, objects
that handle preferences and registry settings, objects used for logging, and objects that act as
device drivers to devices like printers and graphics cards. In fact, for many of these types of
objects, if we were to instantiate more than one we'd run into all sorts of problems like
incorrect program behavior, overuse of resources, or inconsistent results.
Developer: Okay, so maybe there are classes that should only be instantiated once, but do I
need a whole class for this? Can't I just do this by convention or by global variables? You know,
like in Java, I could do it with a static variable.
Guru: In many ways, the Singleton Pattern is a convention for ensuring one and only one object is instantiated for a given class.
If you've got a better one, the world would like to hear about it; but remember, like all patterns, the Singleton Pattern is a
time-tested method for ensuring only one object gets created. The Singleton Pattern also gives us a global point of access,
just like a global variable, but without the downsides.
Developer: What downsides?
Guru: Well, here's one example: if you assign an object to a global variable, then you have to create that object when your application
begins. Right? What if this object is resource intensive and your application never ends up using it? As you will see, with the Singleton
Pattern, we can create our objects only when they are needed.
Developer: This still doesn't seem like it should be so difficult.
Guru: If you've got a good handle on static class variables and methods as well as access modifiers, it's not. But, in either case, it is
interesting to see how a Singleton works, and, as simple as it sounds, Singleton code is hard to get right. Just ask yourself: how do I
prevent more than one object from being instantiated? It's not so obvious, is it?

2
The Little Singleton
How would you create a single object? new MyObject();

And, what if another object wanted to create a Yes, of course.


MyObject? Could it call new on MyObject again?

So as long as we have a class, can we always instantiate Yes. Well, only if it's a public class.
it one or more times?

And if not? Well, if it's not a public class, only classes in the
same package can instantiate it. But they can still
instantiate it more than once.

Hmm, interesting. No, I'd never thought of it, but I guess it makes
Did you know you could do this? sense because it is a legal definition.
public MyClass {
private MyClass() {}
}
3
The Little Singleton
What does it mean? I suppose it is a class that can't be instantiated
because it has a private constructor.

Well, is there ANY object that could use the private Hmm, I think the code in MyClass is the only code
constructor? that could call it. But that doesn't make much sense.

Why not? Because I'd have to have an instance of the class


to call it, but I can't have an instance because no
other class can instantiate it. It's a chicken and
egg problem: I can use the constructor from an
object of type MyClass, but I can never
instantiate that object because no other object
can use "new MyClass()".

4
The Little Singleton
Okay, it was just a thought. MyClass is a class with a static method. We
What does this mean? can call the static method like this:
public MyClass {
public static MyClass getInstance(){} [Link]();
}

Why did you use MyClass, instead of some object name? Well, getInstance() is a static method; in
other words, it is a CLASS method. You need to
use the class name to reference a static method.
Very interesting. What if we put things together. Wow; you sure can.
Now can I instantiate a MyClass?
public MyClass {
private MyClass() {}
public static MyClass getInstance(){
return new MyClass();
}
}
5
The Little Singleton
So, now can you think of a second way to [Link]();
instantiate an object?

Can you finish the code so that only ONE instance of Yes, I think so…
MyClass is ever created?

OK, LET'S FINISH THE CODE!

6
Dissecting the classic Singleton Pattern implementation

public class Singleton {


private static Singleton uniqueInstance;
// other useful instance variables here
private Singleton() { }
public static Singleton getInstance() {
if(uniqueInstance == null) {
uniqueInstance = new Singleton();
}
return uniqueInstance;
}
// other useful methods here
}
7
Code Up Close

8
public class ChocolateBoiler {
private boolean empty;
private boolean boiled;
public ChocolateBoiler() {
The Chocolate Factory
empty = true; Everyone knows that all modern
boiled = false;
} chocolate factories have computer
public void fill() { controlled chocolate boilers. The job
if (isEmpty()) {
empty = false;
of the boiler is to take in chocolate
boiled = false; and milk, bring them to a boil, and
// fill the boiler with a milk/chocolate mixture then pass them on to the next phase
}
}
of making chocolate bars.
public void drain() {
if (!isEmpty() && isBoiled()) {
// drain the boiled milk and chocolate
empty = true;
}
}
public void boil() {
if (!isEmpty() && !isBoiled()) {
// bring the contents to a boil
boiled = true;
}
Here's the controller class for Choc-O-Holic, Inc.'s
} industrial strength Chocolate Boiler. Check out the code;
public boolean isEmpty() { you'll notice they've tried to be very careful to ensure that
return empty;
} bad things don't happen, like draining 500 gallons of
public boolean isBoiled() { unboiled mixture, or filling the boiler when it's already full,
return boiled; or boiling an empty boiler!
}
}
9
Sharpen your pencil

private static ChocolateBoiler uniqueInstance;

private

public static ChocolateBoiler getInstance() {


Can you help Choc-O-Holic improve their if (uniqueInstance == null) {
ChocolateBoiler class by turning it into a }
uniqueInstance = new ChocolateBoiler();

Singleton? return uniqueInstance;


}

10
Singleton Pattern defined
No big surprises there.
But, let's break it down a bit more:
▪ What's really going on here? We're taking a class and letting it manage a single instance of itself. We're also preventing any other class
from creating a new instance on its own. To get an instance, you've got to go through the class itself.
▪ We're also providing a global access point to the instance: whenever you need an instance, just query the class and it will hand you back
the single instance. As you've seen, we can implement this so that the Singleton is created in a lazy manner, which is especially important
for resource intensive objects.

11
Houston, we have a problem…
ChocolateBoiler's fill() method was able to start
filling the boiler even though a batch of milk and
chocolate was already boiling! That's 500 gallons
of spilled milk (and chocolate)! What happened!?

Could the addition of threads have caused this? Isn't


it the case that once we've set the uniquelnstance
variable to the sole instance of ChocolateBoiler, all
calls to getlnstance() should return the same
instance? Right?

12
Be the JVM
We have two threads, each executing this
code. Your job is to play the JVM and
determine whether there is a case in which
two threads might get ahold of different
boiler objects.
Hint: you really just need to look at the
sequence of operations in the
getInstance() method and the value of
uniqueInstance to see how they might
overlap. Use the code Magnets to help, you
study how the code might interleave to
create two boiler objects.

13
Dealing with multithreading
public class Singleton {
private static Singleton uniqueInstance;
// other useful instance variables here

private Singleton() {}

public static synchronized Singleton getInstance() {


if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
return uniqueInstance;
} Good point, and it's actually a little worse than you
// other useful methods here make out the only time synchronization is relevant is
} the first time through this method. In other words,
once we've set the uniqueInstance variable to an
instance of Singleton, we have no further need to
synchronize this method. After the first time through,
synchronization is totally unneeded overhead!
14
Can we improve multithreading?
1. Do nothing if the performance of getInstance() isn’t critical to your application
• Synchronizing getInstance() is straightforward and effective
• Just keep in mind that synchronizing a method can decrease performance by a factor of 100,
so if a high traffic part of your code begins using the method, you may have to reconsider.

2. Move to an eagerly created instance rather than a lazily created one


• Using this approach, we rely on the JVM to create the unique instance of the Singleton when
the class is loaded. The JVM guarantees that the instance will be created before any thread
accesses the static uniquelnstance variable.
public class Singleton {
private static Singleton uniqueInstance = new Singleton();

private Singleton() {}

public static Singleton getInstance() {


return uniqueInstance;
}
}
15
Can we improve multithreading? continued…
3. Use “double-checked locking” to reduce the use of synchronization in getInstance()
• first check to see if an instance is created
• if not THEN synchronize
public class Singleton {
private volatile static Singleton uniqueInstance;

private Singleton() {}

public static Singleton getInstance() {


if (uniqueInstance == null) {
synchronized ([Link]) {
if (uniqueInstance == null) {
uniqueInstance = new Singleton(); If performance is an issue
} in use of getInstance()

}
}
}

return uniqueInstance; ! method then this method


can drastically reduce the
overhead.
}
16
Meanwhile, back at the Chocolate Factory
Sharpen your pencil
For each solution, describe its applicability to the problem of fixing the Chocolate Boiler code

Synchronize the getInstance() method


A straightforward technique that is guaranteed to work. We don’t seem to have any
_________________________________________________________________________________
performance concerns with the chocolate boiler, so this would be a good choice.
_________________________________________________________________________________
_________________________________________________________________________________

Use eager instantiation


We are always going to instantiate the chocolate boiler in our code, so statically initializing
_________________________________________________________________________________
the instance would cause no concerns. This solution would work as well as the synchronized
_________________________________________________________________________________
method, although perhaps be less obvious to a developer familiar with the standard pattern
_________________________________________________________________________________

Double-checked locking
Given we have no performance concerns, double-checked locking seems like overkill. In addition,
_________________________________________________________________________________
we’d have to ensure that we are running at least Java 5.
_________________________________________________________________________________
_________________________________________________________________________________

17
there are no
Dumb Questions
Q: Such a simple pattern consisting of only one class, Q: What about class loaders? I heard there is a chance that
Singletons sure seem to have some problems. two class loaders could each end up with their own instance of
Singleton.
A: Well, you’re warned up front! But don't let the problems
discourage you; while implementing Singletons correctly can A: Yes, that is true as each class loader defines a namespace.
be tricky, after this class you are now well informed on the If you have two or more classloaders, you can load the same
techniques for creating Singletons and should use them class multiple times (once in each classloader). Now, if that
wherever you need to control the number of instances you class happens to be a Singleton, then since we have more than
are creating. one version of the class, we also have more than one instance
of the Singleton. So, if you are using multiple classloaders
Q: I just create a class in which all methods and variables are
and Singletons, be careful. One way around this problem is to
defined as static? Wouldn't that be the same as a Singleton?
specify the classloader yourself.
A: Yes, if your class is self-contained and doesn't depend on
complex initialization. However, because of the way static
initializations are handled in Java, this can get very messy,
especially if multiple classes are involved. Often this scenario
can result in subtle, hard to find bugs involving order of
initialization. Unless there is a compelling need to implement
your "singleton" this way, it is far better to stay in the
object world.

18
there are no
Dumb Questions
Q: I've always been taught that a class should do one thing Q: I wanted to subclass my Singleton code, but I ran into
and one thing only. For a class to do two things is problems. Is it okay to subclass a Singleton?
considered bad 00 design. Isn't a Singleton violating this?
A: One problem with subclassing Singleton is that the
A: You would be referring to the "One Class, One constructor is private. You can't extend a class with a private
Responsibility" principle, and yes, you are correct, the constructor. So, the first thing you'll have to do is change
Singleton is not only responsible for managing its one your constructor so that it's public or protected. But then,
instance (and providing global access), it is also responsible it's not really a Singleton anymore, because other classes can
for whatever its main role is in your application. So, instantiate it. If you do change your constructor, there's
certainly it can be argued it is taking on two responsibilities. another issue. The implementation of Singleton is based on a
Nevertheless, it isn't hard to see that there is utility in a static variable, so if you do a straightforward subclass, all of
class managing its own instance; it certainly makes the your derived classes will share the same instance variable. This
overall design simpler. In addition, many developers are is probably not what you had in mind. So, for subclassing to
familiar with the Singleton pattern as it is in wide use. That work, implementing registry of sorts is required in the base
said, some developers do feel the need to abstract out the class. Before implementing such a scheme, you should ask
Singleton functionality. yourself what you are really gaining from subclassing a
Singleton. Like most patterns, the Singleton is not
necessarily meant to be a solution that can fit into a library. In
addition, the Singleton code is trivial to add to any existing
class.

19
there are no
Dumb Questions
Q: I still don't totally understand why global variables are
worse than a Singleton.
A: In Java, global variables are basically static references to
objects. There are a couple of disadvantages to using global
variables in this manner. We've already mentioned one: the
issue of lazy versus eager instantiation. But we need to keep
in mind the intent of the pattern: to ensure only one
instance of a class exists and to provide global access. A
global variable can provide the latter, but not the former.
Global variables also tend to encourage developers to pollute
the namespace with lots of global references to small
objects. Singletons don't encourage this in the same way,
but can be abused nonetheless.

20
Tools for your Design Toolbox
Bullet Points
▪ The Singleton Pattern ensures you have at most one
instance of a class in your application.
▪ The Singleton Pattern also provides a global access point
to that instance.
▪ Java's implementation of the Singleton Pattern makes use
of a private constructor, a static method combined with a
static variable.
▪ Examine your performance and resource constraints and
carefully choose an appropriate Singleton implementation
for multithreaded applications (and we should consider all
applications multithreaded!).
▪ Beware of the double-checked locking implementation; it is
not thread-safe in versions before Java 2, version 5.
▪ Be careful, if you’re using multiple classloaders.

21

Common questions

Powered by AI

In a multithreaded environment, the Singleton Pattern ensures that resource-intensive objects like a chocolate boiler are not instantiated more than once, preventing race conditions or inconsistent states, such as filling a boiler that is already boiling, as noted in the ChocolateBoiler example . By synchronizing the getInstance() method or using double-checked locking, Singleton prevents multiple threads from creating different instances . These strategies curb instances where simultaneous threads might have otherwise initiated multiple objects, thereby safeguarding the integrity of operations like boiling and draining .

The Singleton Pattern achieves single instance enforcement through a private constructor, which prevents direct instantiation of the class outside its definition, and a static method that serves as the access point for the instance . By using a static variable to hold the single instance, the class itself controls instantiation and only creates the object when requested via the public static method, ensuring that any call to retrieve the instance provides the same object each time . This design prevents any external class from creating another instance, shielding the application from potential instantiation issues .

Subclassing a Singleton class can violate the singleton principle by needing to change the constructor's visibility from private to protected or public, thereby allowing other classes to instantiate it and undermining the single instance restriction . Additionally, since a Singleton relies on a static variable to maintain its instance, subclasses would share this instance variable, leading to unexpected behavior where the derived classes unintentionally share the same instance, defeating the purpose of subclassing . This can complicate the design and potentially introduce errors due to shared state among different subclasses.

Lazy instantiation is preferable over eager instantiation when dealing with objects that are expensive to create or may not always be needed, as it delays creation until the instance is specifically required, thus conserving resources . This approach can improve application performance and resource management by preventing unnecessary loading, thus avoiding the cost of instantiation if the object is never accessed during the application's lifecycle . If an instance is guaranteed to be needed, eager instantiation could be appropriate as it avoids synchronization overhead, but for conditional, less certain use cases, lazy instantiation offers optimal resource utilization .

The Singleton Pattern controls object instantiation by ensuring only one instance of a class exists, while providing global access to it, which prevents incorrect program behavior, inconsistent states, or resource wastage by avoiding multiple instantiations . Unlike global variables which must be initialized at application start, potentially creating unused resource-intensive objects, the Singleton Pattern supports lazy instantiation, creating objects only when needed, thus saving resources . Moreover, global variables, being static, can clutter the namespace and don't ensure a single instance, whereas Singletons define such constraints clearly .

Thread interference during the execution of the getInstance() method can cause inconsistent program behavior if two threads pass the null check at the same time before any has set the uniqueInstance variable, potentially resulting in multiple instantiations of the Singleton . This leads to critical violations of the Singleton principle, causing errors like concurrent state changes or resource mishandling in single-instance devices or processes. Preventing this requires synchronization of the method or u/tructural approaches like double-checked locking in newer Java versions .

Developers might avoid using double-checked locking in Java versions before 5 because it is not thread-safe due to issues with the Java memory model of these versions . The variable might appear non-null to threads before it is fully initialized, leading to potential issues where threads could operate on an incompletely constructed instance, thus breaking the assumptions Singleton Pattern is designed to uphold . Consequently, relying on eager initialization or synchronized methods are safer alternatives in older Java versions.

Class loaders in Java define namespaces, meaning that if a Singleton class is loaded by multiple class loaders, each could instantiate its version of the Singleton, leading to multiple instances instead of just one . This undermines the Singleton’s primary aim of enforcing a single instance per application. Different class loader instances can coexist due to isolation of namespaces, especially in complex applications using modular or plugin architectures where different modules might load the class separately . Proper management of class loaders or specifying a single class loader for the Singleton class can mitigate this issue.

Implementing all class methods and variables as static might be akin to the Singleton Pattern in a scenario where a class is fully self-contained and does not rely on complex initialization, enabling a single point of access similar to Singleton intended use . However, this approach is less recommended because of the complexity and subtle bugs that arise from static initialization, especially when multiple classes become involved or when order of initialization issues occur . Singleton is preferred as it encapsulates instantiation control and resource management within object orientation, preserving design principles better than static methods can .

Synchronization within the getInstance() method is only crucial during the initial check and creation of the Singleton instance. Once an instance is created and the static variable is set, the costly overhead of synchronization becomes redundant since subsequent invocations only need to read the already initialized Singleton instance, which doesn’t require thread-safety . This is because after the static variable is assigned to the Singleton instance, all calls return the established instance, hence synchronization adds unnecessary performance costs without improving safety .

You might also like