单例模式
单例模式实现方式很多:饿汉、懒汉、枚举、静态内部类等
转自:https://www.jianshu.com/p/b8c578b07fbc
为什么要用单例模式?
场景 对于一些类(多为工具类)来说,整个系统中只需要一个实例就可以完成任务,比如:日志打印类、获取线程池类等
优点
- 系统只存在一个对象,可以节约系统资源,减少了频繁创建、销毁对象的开销,提高了系统性能。
缺点
- 如果实例化的对象长时间不被使用,会被系统认为是垃圾而被回收,这将导致对象状态的丢失。
实现方式
- 懒汉模式
/**
* <饿汉模式>
* <p>
* 类一旦加载就创建instance实例,getInstance时实例已经存在
*
* @author dkangel
*/
public class SingletonHungry {
private static final SingletonHungry instance = new SingletonHungry();
/**
* 私有构造方法,避免其他类创建实例
*/
private SingletonHungry() {
}
public static SingletonHungry getInstance() {
return instance;
}
}
- 饿汉模式
/**
* <懒汉模式>
* 只有在getInstance时才去实例化instance
* <p>
* <应用场景>
* 除了初始化单例类时 即 创建单例外,继续延伸出来的是:单例对象 要求初始化速度快 & 占用内存小
*
* @author dkangel
*/
public class SingletonLazy {
/**
* volatile 保证指令重排序的正确性
*/
private volatile static SingletonLazy instance;
/**
* 私有构造方法,避免其他类创建实例
*/
private SingletonLazy() {
}
/**
* <双重校验锁机制>
* <p>
* 第一个if:若实例已经创建,则直接返回,无需加锁
* <p>
* 第二个if:避免多次创建实例
* 如果有两个线程同时调用getInstance()方法,线程A先获取到锁,线程B等待线程A释放锁
* 当线程A执行instance = new SingletonLazy();完毕,释放了锁,此时线程B获取到锁
* 假如没有第二个if判空,则线程B也会执行instance = new SingletonLazy();
* 这样就导致创建了多余的实例
*
* @return SingletonLazy
*/
public static SingletonLazy getInstance() {
if (instance == null) {
synchronized (SingletonLazy.class) {
if (instance == null) {
instance = new SingletonLazy();
}
}
}
return instance;
}
/**
* <同步锁>
* <p>
* 每次访问都要进行线程同步(即 调用synchronized锁)
* 造成过多的同步开销(加锁 = 耗时、耗能)
*
* @return SingletonLazy
*/
public static synchronized SingletonLazy getInstance1() {
if (instance == null) {
instance = new SingletonLazy();
}
return instance;
}
}