文章目录
饿汉式优点缺点
懒汉式优点缺点
懒汉式加锁优点缺点
懒汉式双重检查锁优点缺点
静态内部类式优点
枚举类优点缺点
真的没有缺点吗?常用哪一种?
饿汉式
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() {
}
}
优点
代码简洁、线程安全
缺点
没有
真的没有缺点吗?
除了枚举类型,上述其他类型都可以通过反射来创建多个对象,但是还是可以更改构造方法去解决的。
private Singleton(){
if (instance
!= null
){
throw new RuntimeException("已经实例化");
}
}
除了枚举类型,上述其他类型如果实现了Serializable,那么都可以通过反序列化来出创建多个对象,解决方法:重写反序列化方法readResolve(),反序列化时直接返回已经实例化的对象
public Object
readResolve() throws ObjectStreamException
{
return instance
;
}
常用哪一种?
懒汉式双重检查锁、静态内部类、枚举类