饿汉式
public class Singleton {
private final static Singleton instance = new Singleton();
private Singleton() {
}
public static Singleton getInstance() {
return instance;
}
}
- 为什么叫这个名字?因为这个类太饿了,刚被加载就想实例化填饱肚子
- final的作用是instance被初始化后,instance不可被改变
- 第一个static的作用是当类被加载时,instance就会被初始化
优点
线程安全
缺点
该类被加载就会初始化instance,如果没有被使用到,会浪费资源
懒汉式
public class Singleton {
private static Singleton instance;
private Singleton() {
}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
- 为什么叫这个名字?因为别的类不调用他的方法,他就不实例化,比较懒
- instance如果添加final关键字的话,instance必须在类被加载就初始化,而该方式是调用到getInstance方法才初始化,所以不能添加final关键字
优点
只有调用方法时,才会初始化
缺点
线程不安全
懒汉式加锁
public class Singleton {
private static Singleton instance;
private Singleton() {
}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
- 添加了synchronized关键字,当第一个线程进入该方法后,会持有该锁,此时另一个线程不能进入该方法,直到第一个线程完成方法,将锁释放,第二个线程才可以进入方法
优点
线程安全
缺点
当instance被初始化后,再有线程进入到getInstance方法时,锁就没有意义了,if (instance == null) 这行代码的后续就永远都不会执行,每次需要等待上一个线程返回instance后,再执行下一个线程。
懒汉式双重检查锁
public class Singleton {
private volatitle static Singleton instance;
private Singleton() {
}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
- volatitle的作用
- synchronized的作用
优点
线程安全,解决了上一种方法的缺点
缺点
没有
静态内部类式
public class Singleton {
private Singleton() {
}
private static class Inner {
private final static Singleton instance = new Singleton();
}
public static Singleton getInstance() {
return Inner.instance;
}
}
- 如何保证的线程安全:当线程A、B同时想要获取类的初始化锁,A先拿到后,完成初始化,释放锁,B获得初始化锁,发现对象已经初始化完毕,释放锁,直接返回已经初始化的对象
优点
代码简洁、线程安全
枚举类
public enum Singleton {
INSTANCE;
public void doSomething() {
//doSomething
}
}
优点
代码简洁、线程安全
缺点
没有
真的没有缺点吗?
- 除了枚举类型,上述其他类型都可以通过反射来创建多个对象,但是还是可以更改构造方法去解决的。
private Singleton(){
if (instance != null){
throw new RuntimeException("已经实例化");
}
}
- 除了枚举类型,上述其他类型如果实现了Serializable,那么都可以通过反序列化来出创建多个对象,解决方法:重写反序列化方法readResolve(),反序列化时直接返回已经实例化的对象
public Object readResolve() throws ObjectStreamException {
return instance;
}
常用哪一种?
懒汉式双重检查锁、静态内部类、枚举类