Design Pattern (2) — Abstract Factory pattern
Next: Design pattern (4) — prototype pattern
An overview,
Official explanation: Ensure a class has only one instance, and provide a global point of access to it.
Singleton pattern is one of the design patterns with the most types of implementation. This paper gives seven implementation patterns, hungry, lazy, static inner class, static code block, singleton pattern in the case of enumeration and serialization, singleton pattern in the case of reflection.
Actor: Singleton Singleton class
Class diagram:
Second, code analysis
2.1 the hungry
First, privatize the constructor;
The second step is initialization at definition time.
Third, define the getInstance() method to return an instance of the object.
Step 4: Create a thread class to verify thread safety (this step is optional to verify the thread safety of this singleton implementation)
public class SingleInstance {
public static void main(String[] args) {
MyThread _tMyThread=new MyThread();
MyThread _tMyThread2=new MyThread();
MyThread _tMyThread3=newMyThread(); _tMyThread.start(); _tMyThread2.start(); _tMyThread3.start(); }}class SingleObject{
private SingleObject(a){ // The first privatized constructor disallows clients to create new objects with new
}
// The second step provides a new object entry
private static SingleObject _sSingleObject=new SingleObject();// It is thread safe to initialize when hanky-hank is defined
// The static method ensures that the client can be called using the class name (i.e. the client can call this method when no new object is created)
public static SingleObject getInstance(a){
return_sSingleObject; }}class MyThread extends Thread{ The thread class is used to test thread safety
@Override
public void run(a) { System.out.println(SingleObject.getInstance().hashCode()); }}Copy the code
Output:
389269157
389269157
389269157
Copy the code
2.2 LanHanShi
First, privatize the constructor;
Second, create a singleton reference and initialize it in the constructor.
Third, define the getInstance() method to return an instance of the object.
Step 4: Create a thread class to verify thread safety (this step is optional to verify the thread safety of this singleton implementation).
2.2.1 Slacker — Threads are not safe
public class SingleInstance {
public static void main(String[] args) {
for (int i=0; i<10; i++){// Simulate 10 threads
newMyThread().start(); }}}class SingleObject{
private SingleObject(a){ // The first privatized constructor disallows clients to create new objects with new
}
private static SingleObject _sSingleObject;
// The static method ensures that the client can be called using the class name (i.e. the client can call this method when no new object is created)
public static SingleObject getInstance(a) throws Exception{
Thread.sleep(5000); // Thread unsafe issues are exposed by waiting for 5s with sleep ()
if (_sSingleObject==null) {
_sSingleObject=new SingleObject();
}
return_sSingleObject; }}class MyThread extends Thread{ The thread class is used to test thread safety
@Override
public void run(a) {
try {
System.out.println(SingleObject.getInstance().hashCode());
} catch (Exception e) {
// TODO Auto-generated catch blocke.printStackTrace(); }}}Copy the code
Output:
193202248
412303685
193202248
193202248
193202248
389269157
193202248
1435984462
193202248
193202248
Copy the code
2.2.2 Synchronize synchronization to ensure thread security
public class SingleInstance {
public static void main(String[] args) {
for (int i=0; i<10; i++){// Simulate 10 threads
newMyThread().start(); }}}class SingleObject{
private SingleObject(a){ // The first privatized constructor disallows clients to create new objects with new
}
private static SingleObject _sSingleObject;
// The static method ensures that the client can be called using the class name (i.e. the client can call this method when no new object is created)
public static synchronized SingleObject getInstance(a) throws Exception{
Thread.sleep(5000); // Thread unsafe issues are exposed by waiting for 5s with sleep ()
if (_sSingleObject==null) {
_sSingleObject=new SingleObject();
}
return_sSingleObject; }}class MyThread extends Thread{ The thread class is used to test thread safety
@Override
public void run(a) {
try {
System.out.println(SingleObject.getInstance().hashCode());
} catch (Exception e) {
// TODO Auto-generated catch blocke.printStackTrace(); }}}Copy the code
Output:
968687297
968687297
968687297
968687297
968687297
968687297
968687297
968687297
968687297
968687297
Copy the code
2.2.3 Synchronized code blocks ensure thread safety
public class SingleInstance {
public static void main(String[] args) {
for (int i=0; i<10; i++){// Simulate 10 threads
newMyThread().start(); }}}class SingleObject{
private SingleObject(a){ // The first privatized constructor disallows clients to create new objects with new
}
private static SingleObject _sSingleObject;
// The static method ensures that the client can be called using the class name (i.e. the client can call this method when no new object is created)
public static SingleObject getInstance(a) throws Exception{
Thread.sleep(5000); // Thread unsafe issues are exposed by waiting for 5s with sleep ()
synchronized (SingleObject.class) { // Place the code that needs to be atomized in the synchronization block. The synchronization lock for static methods is bytecode class. The synchronization lock for non-static methods is this
// The synchronized code block synchronizes less content and is more efficient than the synchronized method
if (_sSingleObject==null) {
_sSingleObject=newSingleObject(); }}return_sSingleObject; }}class MyThread extends Thread{ The thread class is used to test thread safety
@Override
public void run(a) {
try {
System.out.println(SingleObject.getInstance().hashCode());
} catch (Exception e) {
// TODO Auto-generated catch blocke.printStackTrace(); }}}Copy the code
Output:
774856018
774856018
774856018
774856018
774856018
774856018
774856018
774856018
774856018
774856018
Copy the code
2.2.4 Lazy lock mechanism ensures thread safety
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class SingleInstance {
public static void main(String[] args) {
for (int i=0; i<10; i++){// Simulate 10 threads
newMyThread().start(); }}}class SingleObject{
private SingleObject(a){ // The first privatized constructor disallows clients to create new objects with new
}
private static Lock lock=new ReentrantLock();
private static SingleObject _sSingleObject;
// The static method ensures that the client can be called using the class name (i.e. the client can call this method when no new object is created)
public static SingleObject getInstance(a) throws Exception{
Thread.sleep(5000); // Thread unsafe issues are exposed by waiting for 5s with sleep ()
lock.lock();
try {
if (_sSingleObject==null) {
_sSingleObject=newSingleObject(); }}finally {
lock.unlock();
}
return_sSingleObject; }}class MyThread extends Thread{ The thread class is used to test thread safety
@Override
public void run(a) {
try {
System.out.println(SingleObject.getInstance().hashCode());
} catch (Exception e) {
// TODO Auto-generated catch blocke.printStackTrace(); }}}Copy the code
Output:
774856018
774856018
774856018
774856018
774856018
774856018
774856018
774856018
774856018
774856018
Copy the code
This approach is similar to hanky-hank, except that the singleton variables are defined and initialized in a static inner class
First, privatize the constructor;
Second, create a singleton reference and initialize it in a static inner class.
Third, define the getInstance() method to return an instance of the object.
Step 4: Create a thread class to verify thread safety (this step is optional to verify the thread safety of this singleton implementation).
public class SingleInstance {
public static void main(String[] args) {
for (int i=0; i<10; i++){// Simulate 10 threads
newMyThread().start(); }}}class SingleObject{
private SingleObject(a){ // The first privatized constructor disallows clients to create new objects with new
}
private static class InnerClass{
private static SingleObject _sSingleObject=new SingleObject();
}
// The static method ensures that the client can be called using the class name (i.e. the client can call this method when no new object is created)
public static SingleObject getInstance(a) throws Exception{
Thread.sleep(5000); // Thread unsafe issues are exposed by waiting for 5s with sleep ()
return InnerClass._sSingleObject; // An inner class member can be accessed from an outer class}}class MyThread extends Thread{ The thread class is used to test thread safety
@Override
public void run(a) {
try {
System.out.println(SingleObject.getInstance().hashCode());
} catch (Exception e) {
// TODO Auto-generated catch blocke.printStackTrace(); }}}Copy the code
Output:
389269157
389269157
389269157
389269157
389269157
389269157
389269157
389269157
389269157
389269157
Copy the code
This approach is similar to hanhan-style, except that the singleton variables are defined and initialized in a static code block
First, privatize the constructor;
Second, create a singleton reference and initialize it in a static code block.
Third, define the getInstance() method to return an instance of the object.
Step 4: Create a thread class to verify thread safety (this step is optional to verify the thread safety of this singleton implementation).
public class SingleInstance {
public static void main(String[] args) {
for (int i=0; i<10; i++){// Simulate 10 threads
newMyThread().start(); }}}class SingleObject{
private SingleObject(a){ // The first privatized constructor disallows clients to create new objects with new
}
private static SingleObject _sSingleObject;
static {
_sSingleObject=new SingleObject();
}
// The static method ensures that the client can be called using the class name (i.e. the client can call this method when no new object is created)
public static SingleObject getInstance(a) throws Exception{
Thread.sleep(5000); // Thread unsafe issues are exposed by waiting for 5s with sleep ()
return _sSingleObject; // An inner class member can be accessed from an outer class}}class MyThread extends Thread{ The thread class is used to test thread safety
@Override
public void run(a) {
try {
System.out.println(SingleObject.getInstance().hashCode());
} catch (Exception e) {
// TODO Auto-generated catch blocke.printStackTrace(); }}}Copy the code
Output:
1742654687
1742654687
1742654687
1742654687
1742654687
1742654687
1742654687
1742654687
1742654687
1742654687
Copy the code
2.5 Use enumeration to achieve singleton thread safety
First, privatize the constructor;
Second, create a singleton reference and initialize it in the constructor.
Third, define the getInstance() method to return an instance of the object.
Step 4: Create a thread class to verify thread safety (this step is optional to verify the thread safety of this singleton implementation).
public class SingleInstance {
public static void main(String[] args) {
for (int i = 0; i < 10; i++) { // Simulate 10 threads
newMyThread().start(); }}}enum SingleObject {
_singleFactory; / / the enumeration
SingleObject() {
_sSingleObject = new String("Single");
}
private String _sSingleObject;
public String getInstance(a) throws Exception {
Thread.sleep(5000); // Thread unsafe issues are exposed by waiting for 5s with sleep ()
return_sSingleObject; }}class MyThread extends Thread { The thread class is used to test thread safety
@Override
public void run(a) {
try {
System.out.println(SingleObject._singleFactory.getInstance().hashCode());
} catch (Exception e) {
// TODO Auto-generated catch blocke.printStackTrace(); }}}Copy the code
Output:
-1818398616
-1818398616
-1818398616
-1818398616
-1818398616
-1818398616
-1818398616
-1818398616
-1818398616
-1818398616
Copy the code
2.6 Serialization breaks singleton patterns and solutions
First, privatize the constructor;
The second step is the initialization of the definition (here we use hanhanian to verify the serialization of the singleton pattern destruction, readers can choose other singleton implementation verification such as lazy, static inner class static code block enumeration);
Third, define the getInstance() method to return an instance of the object. (Hungry Man complete)
Fourth, the singleton class implements Serializable and adds the serial number serializableUid
Fifth, the client reads and writes the singleton and prints hashcode to show the destruction of the singleton pattern by serialization.
Step 6, the readResolve() method in the singleton class protects the singleton schema from serialization.
2.6.1 Serialization breaks singleton patterns
If a singleton implements Serializable, the singleton is broken as follows: implements Serializable
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
public class SingleInstance {
public static void main(String[] args) {
// write to TXT file
try {
SingleObject _sSingleObject = SingleObject.getInstance();
FileOutputStream _oOutputStream = new FileOutputStream(new File("test.txt"));
ObjectOutputStream _oOutputStream2 = new ObjectOutputStream(_oOutputStream);
_oOutputStream2.writeObject(_sSingleObject);
_oOutputStream2.close();
_oOutputStream.close();
System.out.println(_sSingleObject.hashCode());
} catch (Exception e) {
e.printStackTrace();
}
// Read into the program
try {
FileInputStream _iFileInputStream = new FileInputStream(new File("test.txt"));
ObjectInputStream _oInputStream = new ObjectInputStream(_iFileInputStream);
SingleObject _sReaderObject = (SingleObject) _oInputStream.readObject();
_oInputStream.close();
_iFileInputStream.close();
System.out.println(_sReaderObject.hashCode());
} catch(Exception e) { e.printStackTrace(); }}}class SingleObject implements Serializable {
private static final long serializableUid = 1L;
private static final SingleObject _sSingleObject = new SingleObject();
private SingleObject(a) { // Privatize constructor
}
public static SingleObject getInstance(a) {
return_sSingleObject; }}Copy the code
Output:
1550089733
245257410
Copy the code
To resolve this, add a readResolve() method
2.6.2 The readResolve() method protects the singleton schema from serialization
Code:
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
public class SingleInstance {
public static void main(String[] args) {
// write to TXT file
try {
SingleObject _sSingleObject = SingleObject.getInstance();
FileOutputStream _oOutputStream = new FileOutputStream(new File("test.txt"));
ObjectOutputStream _oOutputStream2 = new ObjectOutputStream(_oOutputStream);
_oOutputStream2.writeObject(_sSingleObject);
_oOutputStream2.close();
_oOutputStream.close();
System.out.println(_sSingleObject.hashCode());
} catch (Exception e) {
e.printStackTrace();
}
// Read into the program
try {
FileInputStream _iFileInputStream = new FileInputStream(new File("test.txt"));
ObjectInputStream _oInputStream = new ObjectInputStream(_iFileInputStream);
SingleObject _sReaderObject = (SingleObject) _oInputStream.readObject();
_oInputStream.close();
_iFileInputStream.close();
System.out.println(_sReaderObject.hashCode());
} catch(Exception e) { e.printStackTrace(); }}}class SingleObject implements Serializable {
private static final long serializableUid = 1L;
private static final SingleObject _sSingleObject = new SingleObject();
private SingleObject(a) { // Privatize constructor
}
public static SingleObject getInstance(a) {
return _sSingleObject;
}
protected Object readResolve(a) {
return_sSingleObject; }}Copy the code
Output:
1550089733
1550089733
Copy the code
2.7 Reflection failure singleton mode and its solution
First, privatize the constructor;
The second step, initialization of the definition (here we use hanhanian validation reflection on the destruction of the singleton pattern, the reader can choose other singleton implementation validation such as lazy, static inner class static code block enumeration);
Third, define the getInstance() method to return an instance of the object. (Hungry Man complete)
In step 4, the client creates a new object using reflection and prints hashcode to show how reflection destroys the singleton pattern.
The fifth step, detected in the constructor, throws a runtime exception when the instance is not empty, preventing reflection from creating new objects, and protecting the singleton pattern from reflection in an exceptional way.
Code:
public class SingleInstance {
public static void main(String[] args) throws Exception {
Class<SingleObject> class1 = (Class<SingleObject>) Class.forName("mypackage.SingleObject");
Constructor<SingleObject> constructor = class1.getDeclaredConstructor(null);
constructor.setAccessible(true); SingleObject s1 = constructor.newInstance(); SingleObject s2 = constructor.newInstance(); System.out.println(s1.hashCode()); System.out.println(s2.hashCode()); }}class SingleObject {
private static SingleObject _sSingleObject = new SingleObject();
private SingleObject(a) { // Privatize constructor
}
public static SingleObject getInstance(a) {
return_sSingleObject; }}Copy the code
Output:
366712642
1829164700
Copy the code
Solution: The singleton constructor detects that when the instance object is not empty, it throws a run-time exception to protect the singleton pattern from reflection.
Code:
Output:
public class SingleInstance {
public static void main(String[] args) throws Exception {
Class<SingleObject> class1 = (Class<SingleObject>) Class.forName("mypackage.SingleObject");
Constructor<SingleObject> constructor = class1.getDeclaredConstructor(null);
constructor.setAccessible(true); SingleObject s1 = constructor.newInstance(); SingleObject s2 = constructor.newInstance(); System.out.println(s1.hashCode()); System.out.println(s2.hashCode()); }}class SingleObject {
private static SingleObject _sSingleObject = new SingleObject();
private SingleObject(a) { // Privatize constructor
if(_sSingleObject ! =null)
throw new RuntimeException();
}
public static SingleObject getInstance(a) {
return_sSingleObject; }}Copy the code
Output:
Exception in thread "main" java.lang.reflect.InvocationTargetException
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at mypackage.SingleInstance.main(SingleInstance.java:18)
Caused by: java.lang.RuntimeException
at mypackage.SingleObject.<init>(SingleInstance.java:32)...5 more
Copy the code
Third, summary
The hungry type | Thread safety | Serialization is unsafe, and the readResolve() method protects singletons | Reflection is unsafe and singletons can be protected with exceptions |
---|---|---|---|
LanHanShi | Thread-unsafe (thread-safe can be achieved using static inner classes, static code blocks, and lock mechanisms) | Serialization is unsafe, and the readResolve() method protects singletons | Reflection is unsafe and singletons can be protected with exceptions |
Static inner class | Thread safety | Serialization is unsafe, and the readResolve() method protects singletons | Reflection is unsafe and singletons can be protected with exceptions |
Static code block | Thread safety | Serialization is unsafe, and the readResolve() method protects singletons | Reflection is unsafe and singletons can be protected with exceptions |
Enumeration methods | Thread safety | Serialization is unsafe, and the readResolve() method protects singletons | Reflection is unsafe and singletons can be protected with exceptions |
Design Pattern (2) — Abstract Factory pattern
Next: Design pattern (4) — prototype pattern