Implementation of java singleton

1. Lazy man mode, thread unsafe

/**
 * @author: [email protected]
 * @create: 2018-10-16 11:16
 * @desc:   java单例写法一-懒汉模式,线程不安全
 **/
public class SingletonLazy {
    
    

    private static SingletonLazy instance;

    private SingletonLazy(){
    
    

    }

    public static SingletonLazy getInstance(){
    
    

        if(instance==null){
    
    
            instance=new SingletonLazy();
        }
        return instance;
    }
}

This kind of writing lazy loading is obvious, but the fatal thing is that it cannot work properly in multi-threading.

2. Lazy man mode, thread safety

/**
 * @author: [email protected]
 * @create: 2018-10-16 11:16
 * @desc:   java单例写法二-线程安全
 **/
public class SingletonLazySynchronized {
    
    

    private static SingletonLazySynchronized instance;

    private SingletonLazySynchronized(){
    
    

    }

    public static synchronized SingletonLazySynchronized getInstance(){
    
    

        if(instance==null){
    
    
            instance=new SingletonLazySynchronized();
        }
        return instance;
    }
}

This way of writing can work well in multithreading, and it seems that it also has good lazy loading, but unfortunately, the efficiency is very low, and 99% of the cases do not need synchronization.

3. Hungry man mode

/**
 * @author: [email protected]
 * @create: 2018-10-16 13:38
 * @desc:   java单例写法三-饿汉模式
 **/
public class SingletonHungry {
    
    

    private static SingletonHungry instance=new SingletonHungry();

    public SingletonHungry(){
    
    

    }

    public static SingletonHungry getInstance(){
    
    

        return instance;
    }
}

This method avoids the multi-thread synchronization problem based on the classloader mechanism. However, the instance is instantiated when the class is loaded. Although there are many reasons for class loading, most of them call the getInstance method in the singleton mode, but also It is not sure that there are other ways (or other static methods) to cause class loading. At this time, initializing the instance obviously does not achieve the effect of lazy loading.

4. Hungry man mode, through static code blocks

/**
 * @author: [email protected]
 * @create: 2018-10-16 13:38
 * @desc:   java单例写法四-饿汉模式,通过静态代码块
 **/
public class SingletonHungryStatic {
    
    

    private static SingletonHungryStatic instance;

    static{
    
    
        instance=new SingletonHungryStatic();
    }

    public SingletonHungryStatic(){
    
    

    }

    public static SingletonHungryStatic getInstance(){
    
    

        return instance;
    }
}

On the surface, it seems that the difference is quite large, but in fact it is similar to the third method, which is to instantiate the instance during class initialization.

5. Implement a singleton through a static inner class

/**
 * @author: [email protected]
 * @create: 2018-10-16 13:57
 * @desc:   java单例写法五-静态内部类
 **/
public class SingletonStaticInner {
    
    

    private static class SingletonHandler{
    
    

        private static final SingletonStaticInner INSTANCE=new SingletonStaticInner();
    }

    private SingletonStaticInner(){
    
    }

    public static final SingletonStaticInner getInstance(){
    
    
        return SingletonHandler.INSTANCE;
    }
}

This method also uses the classloder mechanism to ensure that there is only one thread when initializing the instance. It is different from the third and fourth methods (very subtle differences): the third and fourth methods only need the Singleton class is loaded, then the instance will be instantiated (the effect of lazy loading is not achieved), and this way is that the Singleton class is loaded, and the instance is not necessarily initialized. Because the SingletonHolder class is not actively used, the SingletonHolder class will be displayed and loaded only when the getInstance method is called to instantiate the instance. Imagine if instantiating an instance consumes resources, and I want it to be lazy loaded. On the other hand, I don't want to instantiate it when the Singleton class is loaded, because I can't ensure that the Singleton class may be actively used elsewhere. is loaded, it is obviously inappropriate to instantiate instance at this time. At this time, this method is very reasonable compared to the third and fourth methods.

6. Realize singleton through enumeration

/**
 * @author: [email protected]
 * @create: 2018-10-16 14:44
 * @desc:   通过枚举创建单例
 **/
public enum SingletonEnum {
    
    

    INSTANCE;

    private Resouce resouce;
    SingletonEnum(){
    
    
        resouce=new Resouce();
    }

    public Resouce getInstance(){
    
    
        return resouce;
    }

}

class Resouce{
    
    

}

The above class Resource is the resource we want to apply the singleton mode, which can be expressed as network connection, database connection, thread pool and so on.
The way to get resources is very simple, as long as SomeThing.INSTANCE.getInstance() can get the desired instance. Let's take a look at how the singleton is guaranteed:
First, in the enumeration, we made it clear that the construction method is limited to private, and the construction method will be executed when we access the enumeration instance, and each enumeration instance is static final type, which means it can only be instantiated once. Our singleton is instantiated when the constructor is called.
In other words, because the instance in the enum is guaranteed to be instantiated only once, our INSTANCE is also guaranteed to be instantiated once.
It can be seen that enumeration is relatively simple to implement a singleton. In addition, let's take a look at the declaration of the Enum class:

public abstract class Enum<E extends Enum<E>>
        implements Comparable<E>, Serializable

As you can see, enumerations also provide a serialization mechanism. Some cases, such as we want to transfer a database connection handle over the network, will help a lot.
Finally, borrow the words from the book "Effective Java": the single-element enumeration type has become the best way to implement Singleton.

Seven, double check lock to achieve a single case

/**
 * @author: [email protected]
 * @create: 2018-10-16 14:52
 * @desc:   java单例写法七-双重校验锁实现单例-基于方法二
 **/
public class SingletonLazyDoubleSynchronized {
    
    

    private volatile static SingletonLazyDoubleSynchronized instace;

    private SingletonLazyDoubleSynchronized(){
    
    }

    private static SingletonLazyDoubleSynchronized getInstance(){
    
    

        if(instace==null){
    
    
            synchronized (SingletonLazyDoubleSynchronized.class){
    
    
                if(instace==null){
    
    
                    instace=new SingletonLazyDoubleSynchronized();
                }
            }
        }
        return instace;
    }
}

This is an upgraded version of the second method, commonly known as double-check locking. After JDK1.5, double-check locking can normally achieve the singleton effect.

Notice:

There are two issues to be aware of:

1. If the singleton is loaded by different class loaders, there may be multiple instances of the singleton class. Assuming no remote access, for example some servlet containers use a completely different class loader for each servlet, so that if two servlets access a singleton class, they will both have their own instance.

2. If Singleton implements the java.io.Serializable interface, then instances of this class may be serialized and restored. However, if you serialize an object of a singleton class and then restore multiple instances of that object, then you will have multiple instances of the singleton class.

The fix for the first problem is:

private static Class getClass(String classname)      
                                         throws ClassNotFoundException {
    
         
      ClassLoader classLoader = Thread.currentThread().getContextClassLoader();     
      
      if(classLoader == null)     
         classLoader = Singleton.class.getClassLoader();     
      
      return (classLoader.loadClass(classname));     
   }     
}  

The fix for the second problem is:

public class Singleton implements java.io.Serializable {
    
         
   public static Singleton INSTANCE = new Singleton();     
      
   protected Singleton() {
    
         
        
   }     
   private Object readResolve() {
    
         
            return INSTANCE;     
      }    
}   

Guess you like

Origin blog.csdn.net/qa76774730/article/details/83088323