单例模式

定义

单例模式即一个 JVM 内存中只存在一个类的对象实例。

分类

  1. 饿汉式指的是jvm加载类时就创建对象实例,调用效率高,不能延迟加载,影响系统性能,线程安全。具体代码如下:
    /**
     * 饿汉式单例模式:类加载的时候就创建实例
     * 优点:线程安全,类加载时就创建实例,调用效率高
     * 缺点:不能延迟加载,影响系统性能
     */
    public class EagerSingleton {
    /*    //jvm加载类时,就创建实例
        private static EagerSingleton singleton = new EagerSingleton();
        */
    
        private static EagerSingleton singleton=null;
        //在静态代码块中,创建实例,静态块与类同时被jvm加载的
        static {
            singleton = new EagerSingleton();
            //私有构造方法
        }
        private EagerSingleton(){}
    
        //提供一个静态方法给外部调用,获取该单例实例
        public static EagerSingleton getInstance(){
            return singleton;
        }
    
    }
  2. 懒汉式:需要使用实例对象才去创建对象,懒汉式又分二种,线程安全懒汉式,线程不安全懒汉式  线程不安全懒汉式特点:能延迟加载,线程不安全,线程安全懒汉式特点:延迟加载,线程安全,调用效率高。具体代码如下: 
    /**
     * 懒汉式单例模式:使用时才创建实例
     * 分线程安全单例模式,线程不安全单例模式
     * 线程安全懒汉式:
     * 优点:延迟加载,线程安全,
     * 缺点:执行效率低。
     * 线程不安全懒汉式:
     * 优点:延迟加载,
     * 缺点:线程安全
     */
    public class LazySingleton {
    
        private static LazySingleton singleton;
        //私有构造方法
        private LazySingleton(){}
        //1.线程不安全的的懒汉式单例,提供一个非同步的方法,给外部使用者调用,不推荐使用
        /*public static LazySingleton getInstance(){
            if(singleton==null){
                singleton=new LazySingleton();
            }
            return singleton;
        }*/
        //2.线程不安全的的懒汉式单例同步块,只是单检验锁,依然可能创建多个实例
       /* public static LazySingleton getInstance(){
            if(singleton==null){
                synchronized (LazySingleton.class){
                    singleton=new LazySingleton();
                }
    
            }
            return singleton;
        }*/
        // 线程安全的懒汉式:为了解决线程安全,提供一个同步静态方法,给外部使用者调用,但是调用效率低下
        public static synchronized LazySingleton getInstance(){
            if(singleton==null){
                singleton=new LazySingleton();
            }
            return singleton;
        }
    
    
    
    }
  3. 静态内部类单例模式:在静态内部类中创建外部类的实例,能延迟加载,调用效率高,线程安全,具体代码如下:   

    /**
     * 静态内部类单例模式
     * 特点:线程安全,延迟加载,调用效率高,推荐使用
     */
    public class InnerClassInstance {
        //私有的构造
        private InnerClassInstance(){}
        
        //在静态内部类内创建外部类实例。
         private static class InnerSingleton{
             private static final  InnerClassInstance SINGLETON=new InnerClassInstance();
        }
    
        //对外提供一个静态方法,获取该类的实例
        public static final InnerClassInstance getInstance(){
            return InnerSingleton.SINGLETON;
        }
    
    }


  4. 双重检验锁单例模式:实例变量用volatile进行锁定,保证不同线程对实例变量是可见的,再用同步代码块保证创建的实例是单例,是线程安全的,能延迟加载,调用效率比安全的懒汉式单例模式高

    **
     * 双重检验锁单例模式:实例变量用volatile进行锁定,保证不同线程对实例变量是可见的,再用同步代码块保证创建的实例是单例,可以推荐使用
     * 优点:线程安全,可延迟加载
     * 缺点:调用效率不是很高,但比饿汉式同步方法进行锁定的效率要高。
     */
    public class DoubleLockSingleton {
        //volatile修饰实例,1:使得不同线程对该实例是可见的,禁止进行指令重排序
        private static volatile  DoubleLockSingleton singleton;
        //私有的构造方法
        private DoubleLockSingleton(){}
        //对外提供一个获取该单例的方法
        public static DoubleLockSingleton getInstance(){
            if(singleton==null){
                synchronized(DoubleLockSingleton.class){
                    if(singleton==null){
                        singleton=new DoubleLockSingleton();
                    }
                }
            }
            return  singleton;
        }
    
    }
  5.  枚举单例模式:枚举常量是就是枚举类型的一个实例,枚举是天然的单例,代码如下:

    /**
     * 枚举单例,枚举类型是天然的单例,一个成员变量就是枚举的一个实例
     */
    public enum  EnumSingleton {
        SINGLETON;
    }

使用场景 

  1. 工具类对象
  2. 只需要一个对象的类
  3. 创建频繁经常用到的对象

jdk单例的应用 

  1. Runntime类

    public class Runtime {
        private static Runtime currentRuntime = new Runtime();
    
        /**
         * Returns the runtime object associated with the current Java application.
         * Most of the methods of class <code>Runtime</code> are instance
         * methods and must be invoked with respect to the current runtime object.
         *
         * @return  the <code>Runtime</code> object associated with the current
         *          Java application.
         */
        public static Runtime getRuntime() {
            return currentRuntime;
        }
  2. Spring容器内的实例默认是饿汉式单例,即容器启动时就实例化bean到容器,通过defalut-lazy-init="true"设置懒汉式实例化bean,使用到bean,才实例化bean,这就是容器化单例。
原文地址:https://www.cnblogs.com/shareAndStudy/p/12728187.html