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