This article is a reprint of the blog. https://munchkins-diary.hatenablog.com/entry/2018/11/21/040358
Hi, I'm a Java / Scala developer who is willing or unwilling to be cleaned in the JVM after learning G1GC.
The design pattern called the Singleton pattern is very famous, so you probably know it, but Java has various ways to write Singleton using language specifications other than the usual way of writing, so I will introduce it this time. I will. By the way, I didn't know Bill Pugh until I left Japan.
Speaking of the Singleton pattern, when explaining the merits, it is a design pattern that is often abstractly explained, such as being able to create an instance that must be unique in terms of object orientation.
Personally, I often use it when collecting heavy and strong side effects such as communicating with the outside and accessing middleware, and then implementing it in a FlyWeight tick in combination with an abstract factory.
Also, on the contrary, I like to use it when implementing a more object-like implementation without using Util-type classes, where a completely functional implementation is required.
It's not a Singleton pattern, but I have the impression that Spring Bean's Singleton policy is similar to the former usage of Singleton. (It looks like it's going to fly here, so don't miss it. If you have a better way to use it, please leave a comment!)
Then the main subject!
A method of prohibiting new from an outer class and ensuring uniqueness by giving Instance to class value and making constructor private.
class NormalSingleton{
// Singleton instance.
private static final NormalSingleton INSTANCE = new NormalSingleton();
// private constructor to prevent instantiation from other classes.
private NormalSingleton() {}
// static method to get the instance.
public static NormalSingleton getInstance() {
return INSTANCE;
}
}
As you all know, this is the most common way of writing. This is enough for a light class. Since INSTANCE is a static member, it is loaded into the heap when the class is loaded.
There seems to be a way to make INSTANCE public, but personally I don't want to refer to class members directly, so I call it from the public static method.
** ・ Simple and easy to implement ** ** ・ Easy to understand even for beginners ** **-Thread safe **
**-Not suitable for heavy classes because an instance is always created when the class is loaded ** ** · Not strictly a singleton as the constructor is accessible by reflection **
It's a general-purpose implementation method, so I'll mention it, but if I dare to mention it, ** ・ Learning ** ** · Classes that are known to be frequently used on the server side ** **-A class that is not heavy but wants to be a Singleton in an object-oriented sense ** Is it around?
A method that does not have an initial value, creates an instance by calling the getInstance method first, and reuses the created instance from the second time onward.
class DelaySingleton {
// field for singleton instance without any initial value (null)
private static DelaySingleton instance;
// private constructor to block the instantiation from other class.
private DelaySingleton () {}
// method to get the instance
public static getInstance() {
// create instance only in initial call of this method.
if (instance == null) {
instance = new DelaySingleton();
}
return instance;
}
}
This is also a familiar and delayed generation pattern. It is often used in slightly heavier classes. It is often used because it is easy to implement and the mechanism is clear, but as you can see, it is not ThreadSafe, so in an environment where parallel processing is performed, the pattern made into ThreadSafe using Synchronized, which will be introduced next, is used.
** ・ Simple and easy to implement ** ** ・ Easy to understand even for beginners ** **-Can delay heavy class generation until just before it is used **
** ・ Non-thread safe ** ** ・ Because the instance is not final in addition to the constructor, it can be rewritten via reflection, and it is no longer a Singleton **
** ・ Learning ** ** ・ Batch processing that does not use multithreading **
A method of enclosing the place where the instance is created with a synchronization block and firmly narrowing down the new call to one time.
class SynchronizedSingleton {
// field for singleton instance without any initial value (null)
private static SynchronizedSingleton instance;
// private constructor to protect the instantiation from other class.
private SynchronizedSingleton(){}
// method to get the instance
public static SynchronizedSingleton getInstance(){
// check if the instance is already instantiated.
if(instance == null){
// block the multiple access from multiple thread
synchronized (SynchronizedSingleton.class) {
// check again, can be non-null,
// since the instance already generated just at the process just before
if(instance == null){
instance = new SynchronizedSingleton();
}
}
}
return instance;
}
}
This may also be quite familiar. This is the method introduced in design pattern books and many introductory articles. By the way, I honestly don't like this way of writing.
**-Thread safe ** **-The generation of heavy instances can be delayed until just before it is used **
** · and synchronized can lead to performance degradation ** ** ・ Because INSTANCE is not final in addition to the constructor, it can be rewritten via reflection, and it is no longer a Singleton ** ** ・ Redundant and difficult to write and difficult to read **
** ・ Learning ** **-Batch that makes heavy use of multithreading ** ** ・ Server-side application operated by tomcat etc. ** Synchronized Singleton has a lot of problems, so I personally often use Bill Push Singleton, which will be described later. Bill Pugh Singleton Singleton using the Java language specification that the class value of the inner class is not read into memory until the first reference.
class BillPushSingleton{
// class to hold the instance as final
private class SingletonHolder{
// this instance won't be loaded to memory until initial reference
// normally, class value will be loaded into memory when the class is loaded to JVM with class loader.
private static final BillPushSingleton INSTANCE = new BillPushSingleton();
}
// private constructor to prevent instantiation from other classes
private BillPushSingleton() {}
// method to get the instance
public static BillPushSingleton getInstance() {
// this instance will be instantiated at the initial call only.
return SingletonHolder.INSTANCE;
}
}
It may be a writing style that is not very familiar in Japan (as far as I know), but it is a writing style that overseas developers like to use. I also think it's simple and elegant, so basically I use this writing method when making a delayed generation Singleton.
For the time being, the class value of a normal class is instantiated when the class loader loads the class into the JVM, and is stored in the permanent area of the heap. (If you don't know the permanent area, read O'Reilly's Java performance!) However, the constant declared in the inner class is not new when the parent class itself is referenced, but is new and retained in the permanent area only when the parent class refers to the inner class. Will be. This allows INSTANCE in this class to be thread-safe while delaying generation until the getInstance method is called. (Actually, this is a class loader specification, and it's not a special hack.)
** ・ Simple and easy to implement ** **-Thread safe ** **-Can delay the generation of heavy instances until just before they are used ** ** ・ No worries about performance degradation due to synchronization **
**-It is not strictly a Singleton because it can be instantiated via reflection ** ** ・ It's lazy to explain to people who have no knowledge of JVM and class loader (the biggest reason I wrote this article) **
**-Batch that makes heavy use of multithreading ** ** ・ Server-side application operated by tomcat etc. **
By the way, this is still not a strict Singleton. As long as the constructor remains, it can't be a strict Singleton.
Enum Singleton Singleton using Java's language specification that Enum is the only instance globally
enum EnumSingleton {
// enum with only one element.
// this element will act as same with instance of other impl pattern.
INSTANCE("Now it is clear for you to see this is singleton, ahh??");
// Constructor to make this sample code looks like class.
// this constructor is unable to be called even from reflection as Java lang spec.
private EnumSingleton(String dummyMessage) {
this.dummyMessage = dummyMessage;
}
// dummy filed to make this sample code look like the other impl pattern
private String dummyMessage;
// dummy method to show this enum can work like normal class.
public String sampleMethod() {
return "this method is sample to show this is not just the normal enum.";
}
}
This implementation method may be quite famous. As a Java language specification, Enum is a strict Singleton, and you cannot create a new instance even via reflection. Only Singletons implemented as enums are real Singletons. By the way, I think it's normal, so I've never used it just because I know it as knowledge.
** ・ Strict Singleton ** **-Thread safe **
** ・ I don't understand the meaning of enum because the implementation is not good ** ** ・ Interfaces and abstract classes cannot be used, making it difficult to combine with other design patterns ** ** ・ Delay generation is not possible ** ** ・ I can't explain well when asked why I did it **
**-Batch that makes heavy use of multithreading ** ** ・ Server-side application operated by tomcat etc. ** ** ・ Soothes developers who start crying because they can't stand the gap between ideal and reality **
I have introduced various ways to implement the Singleton pattern that I know. Personally, I think I should use only Bill Pugh Singleton and ordinary Singleton. By the way, I often use enum singletons, but it's a traditional writing style, and it's not because I used it. It's a personal story. Well then!
Recommended Posts