目录
- 一、介绍
- 二、饿汉模式
- 三、懒汉模式
- 四、静态内部类
- 五、枚举
- 六、双重校验锁
一、介绍
有些时候我们需要只保存某个类的单个实例,叫做单例Singleton。比如反复的初始化和销毁对象会占用大量的资源,我们就适合使用单例模式。
二、饿汉模式
饿汉需要的是立刻马上就准备好食物,因此饿汉模式为事先创建好对象,等待使用。
public class SingletonDemo1 {
private static SingletonDemo1 singletom = new SingletonDemo1();
private SingletonDemo1() {
// DO SOMETHING;
}
public static SingletonDemo1 getInstance() {
return singletom;
}
}
说明:类被加载的时候就初始化,可能会导致资源的浪费。
三、懒汉模式
懒汉可以理解为事情要拖到最后才去处理。因此懒汉模式事先不初始化,使用之前才创建对象。
public class SingletonDemo2 {
private static SingletonDemo2 instance;
private SingletonDemo2() {
// DO SOMETHING;
}
public synchronized static SingletonDemo2 getInstance() {
if (instance == null) {
instance = new SingletonDemo2();
}
return instance;
}
}
说明:根据是否包含synchronized会有两种不同的结果。
- 不包含synchronized,低并发的时候可能没有问题,在高并发下
if (instance == null)
这个判断可能会出现问题,因为实例还没有初始化完,instance的值还是null,可能会有多个线程同时执行instance = new SingletonDemp2()
这个语句,结果可能比资源浪费还要严重。 - 包含synchronized,低并发没有问题,高并发下不会出现错误和资源浪费,但是处理会变成同步模式,导致效率问题。
四、静态内部类
public class SingletonDemo3 {
private static class SingletonWrap {
public static SingletonDemo3 instance = new SingletonDemo3();
}
private SingletonDemo3() {
// DO SOMETHING;
}
public static SingletonDemo3 getInstance() {
return SingletonWrap.instance;
}
}
说明:没有明显的不足,跟饿汉模式比较接近,又能在使用的时候初始化
五、枚举
public enum SingletonDemo4 {
INSTANCE;
public void doSomething() {
System.out.println("要实现的代码写在这个自定义方法里");
}
public static void main(String[] args) {
SingletonDemo4.INSTANCE.doSomething();
}
}
说明:没有明显的不足,不支持继承(但是使用继承的机会又比较少)
六、双重校验锁
public class SingletonDemo5 {
private volatile static SingletonDemo5 instance;
private SingletonDemo5() {
// DO SOMETHING;
}
public synchronized static SingletonDemo5 getInstance() {
if (instance == null) {
synchronized (SingletonDemo5.class) {
if (instance == null) {
instance = new SingletonDemo5();
}
}
}
return instance;
}
}
说明:需要注意两个变化的地方。
- volatile关键字,用来防止对象创建过程中因为指令重排,从而导致访问到未被初始化完成的对象。
- 两次
if (instance == null)
判断,避免了多线程的排队问题,同时也避免了数据的多次初始化。