一、什么是单例模式
所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法
- 主要解决:一个全局使用的类频繁地创建与销毁。
- 何时使用:当您想控制实例数目,节省系统资源的时候。
- 如何解决:判断系统是否已经有这个单例,如果有则返回,如果没有则创建。
- 关键代码:构造函数是私有的。
注意:
单例类只能有一个实例
单例类必须自己创建自己的唯一实例
单例类必须给所有其他对象提供这一实例
单例模式的利弊
好处:
在内存里只有一个实例,减小了内存的开销
避免了对资源的多重占用
弊端:
没有接口不能继承
二、单例模式的几种实现方式
饿汉式
public class Hungry {
public Hungry() {
}
private final static Hungry HUNGRY = new Hungry();
public static Hungry getInstance() {
return HUNGRY;
}
}
优点:
没有加锁,执行效率会提高
缺点:
类加载就初始化,浪费内存,容易产生垃圾对象
懒汉式
单线程:
public class LazyMan {
private volatile static LazyMan LazyMan;
private LazyMan (){}
public static LazyMan getInstance() {
if (LazyMan == null) {//判断是否被实例化过,等于null表示未实例化过
LazyMan = new LazyMan();
}
return LazyMan;
}
}
多线程
双重检测锁模式DCL:
public class LazyMan {
private volatile static LazyMan LazyMan;
private LazyMan (){}
public static LazyMan getInstance() {
if (LazyMan == null) {//第一重检测
synchronized (LazyMan.class) {
if (LazyMan == null) {//判断是否实例化过
LazyMan = new LazyMan();//不是一个原子性操作
}
}
}
return LazyMan;
}
}
优点:
第一次调用才初始化,避免内存浪费
缺点:
必须加锁才能保证单例,但加锁会影响效率
静态内部类
public class Holder {
private Holder() {
}
public static Holder getInstance() {
return InnerClass.HOLDER;
}
public static class InnerClass {
private static final Holder HOLDER = new Holder();
}