为什么需要单例模式?
保证类的实例在全局只有一个,避免无效对象创建和销毁时的资源消耗。
在Java中一切都是对象,实例方法的调用需要通过对象,为了调用类中的方法而创建对象,方法调用完成之后对象也需要被GC回收,资源消耗较大。
单例模式有多种实现方式
饿汉式
程序启动即创建单例对象,系统运行中减少对象的创建时间,程序启动较慢,运行过程中响应较快,如果程序整个生命周期中没有用到该单例对象会造成资源的浪费(创建对象和销毁对象)。
public class Singleton1 {private Singleton1(){}// 饿汉式,程序启动时创建对象,启动耗时,如果对象在整个声明周期内没有使用那么对象创建及销毁浪费时间private static Singleton1 instance = new Singleton1();public static Singleton1 getInstance() {return instance;}
}
懒汉式
程序启动时不创建对象,在运行的过程中第一次使用时才创建对象,程序启动较快。
同步方法
所有的并发操作都会进行阻塞,效率较低
public class Singleton2 {private Singleton2(){}private static Singleton2 instance = null;public static synchronized Singleton2 getInstance(){if (instance == null) {instance = new Singleton2();}return instance;}
}
DCL
将同步方法修改为同步代码块,为了保证性能和功能需要使用双重锁判断(Double Check Lock)
需要将单例引用使用 volatile 修饰
public class Singleton3 {private Singleton3(){}// DCL 方式需要使用volatile进行修饰private volatile static Singleton3 instance = null;public static Singleton3 getInstance(){// DCL(Double Check Lock) 双重锁检查,保证单例的正确和性能if (instance == null) { // 保证性能,只有第一次并发的线程才会进入代码块内部synchronized (Singleton3.class){if (instance == null) { // 保证正确,第一次并发进来的线程也会进行判断instance = new Singleton3();}}}return instance;}
}
静态内部类
静态内部类在单例类中声明一个持有单例对象的内部类,在获取单例对象时从静态内部类中获取持有的单例对象,方法需要使用 final 修饰。
public class Singleton4 implements Serializable {private Singleton4(){}private static Singleton4 instance = null;private static class SingletonHolder{private static Singleton4 instance = new Singleton4();}public static final Singleton4 getInstance() {return SingletonHolder.instance;}}
以上四种方式都是
1:将单例类的构造函数私有化,
2:在类内部创建对象,
3:通过方法暴漏给用户
如果对单例对象进行序列化和反序列化也将得到不同的对象,这个问题可以在单例类内部添加 readResolve方法 解决。
枚举
"单元素枚举类已成为Singleton的最佳方法。"-----《effective java》
public enum Singleton5 {INSTANCE;int value;private Singleton5(){System.out.println("Singleton5 is created ! ");}public int getValue(){return value;}public void setValue(int value){this.value = value;}}