单例模式


单例模式

单例设计模式,即某个类在整个系统中只能有一个实例对象可被获取和使用的代码模式,eg:jdk中Runtime类就是单例模式

单例模式写法要点:

  • 只能有一个实例:构造器私有化
  • 自行创建这个实例:用静态变量来保存这个唯一实例
  • 对外部暴露这个实例:直接暴露、通过get方法暴露

饿汉式写法

直接创建实例化对象,不管对象是否被需要

写法1

直接实例化饿汉式,简洁直观

package com.yl;

/**
 * 单例模式:饿汉式
 *
 * @author Y-wee
 */
public class Singleton {
    public static final Singleton SINGLETON=new Singleton();

    private Singleton(){}

}

写法2

静态代码块饿汉式,适合复杂实例化(可以在静态代码块中编写实例化前的一些代码逻辑)

package com.yl;

/**
 * 单例模式:饿汉式
 *
 * @author Y-wee
 */
public class Singleton {
    private static final Singleton SINGLETON;

    static {
        // 此处可以编写实例化前的一些代码逻辑
        SINGLETON=new Singleton();
    }

    private Singleton(){}

}

总结:饿汉式是在类加载时就直接创建对象;缺点:如果对象用不到也会被创建创建出来造成内存浪费;优点:不存在线程安全问题

懒汉式写法

在对象被调用时才实例化对象,如果对象一直不被调用就一直不实例化

写法1

package com.yl;

/**
 * 单例模式:懒汉式
 *
 * @author Y-wee
 */
public class Singleton {
    private static Singleton singleton;

    private Singleton() {
    }

    public static Singleton getSINGLETON() {
        if (singleton == null) {
            singleton = new Singleton();
        }
        return singleton;
    }
}

注意:懒汉式写法1适合用于单线程,如果用在多线程场景会出现线程安全问题

写法2

将对象实例化过程放到同步块中,优化线程安全问题

package com.yl;

/**
 * 单例模式:懒汉式
 *
 * @author Y-wee
 */
public class Singleton {
    private static Singleton singleton;

    private Singleton() {
    }

    public static Singleton getSINGLETON() {
        synchronized (Singleton.class){
            if (singleton == null) {
                singleton = new Singleton();
            }
            return singleton;
        }
    }
}

注意:懒汉式写法2虽然解决了线程安全问题,但是每次线程进来都要先获取锁才能判断对象是否实例化,如果并发量大容易造成阻塞,效率低

写法3

在同步代码块外判断对象是否实例化

package com.yl;

/**
 * 单例模式:懒汉式
 *
 * @author Y-wee
 */
public class Singleton {
    private static Singleton singleton;

    private Singleton() {
    }

    public static Singleton getSINGLETON() {
        if (singleton == null) {
            synchronized (Singleton.class) {
                singleton = new Singleton();
            }
        }
        return singleton;
    }
}

写法4

将对象实例化过程放在静态内部类中

package com.yl;

/**
 * 单例模式:懒汉式
 *
 * @author Y-wee
 */
public class Singleton {
    private Singleton() {
    }

    /**
     * 静态内部类不会随着外部类的加载和初始化而初始化,而是在被调用时才初始化
     * 这样既实现了懒汉模式又解决了线程安全问题
     */
    private static class Inner{
        private static final Singleton SINGLETON=new Singleton();
    }

    public static Singleton getSINGLETON() {
        return Inner.SINGLETON;
    }
}