1.什么是单例模式?
当我们new一个对象时会帮我们申请内存地址,每一次去new的时候都会构建不同的地址,而单例模式就是每次获取的实例化对象都保证是同一份。常见的单例模式有8种写法,每一种单例模式都有自己的优缺点,下面让我们来看看这8种单例模式。
1.饿汉模式(推荐)
优点:当类加载到内存后就实例化一个单例,由Jvm保证线程安全,写法超级简单;实际开发中也不会在意是否一定要使用了才进行加载。
缺点:可通过反射和反序列化进行更改,不管是否使用,只要类加载时就会完成实例化。
2.饿汉模式变形(推荐)
这种方式实际上只是饿汉模式的一种变形写法,加载类时由于只会执行一次静态代码块来初始化实例。
3.懒汉模式写法1(不推荐)
优点:解决了只有在使用时才进行实例化单例
缺点:可通过反射和反序列化进行更改,不能多线程环境下使用,线程不安全,当存在多线程环境下时,若第一个线程进入判断singleton为null,当还未进行初始化单例对象时,第二个线程此时判断singleton也为空,所以会继续进行初始化单例对象,此时两次返回的单例实际上并不是同一个。
4.懒汉模式写法2(不推荐)
优点:解决了只有在使用时才进行实例化单例,同时保证线程安全。
缺点:可通过反射和反序列化进行更改;通过对方法上进行synchronized关键字进行加锁,但是由于锁的力度过大,每次都需要进行加锁,即使singleton已经不为空时。
5.懒汉模式写法3(不推荐)
优点:解决了只有在使用时才进行实例化单例
缺点:可通过反射和反序列化进行更改,线程不安全,多线程环境下使用时,若第一个线程进入判断singleton为null,然后拿到锁,当还未进行初始化单例对象时,第二个线程此时判断singleton也为空,所以会继续进行初始化单例对象,此时两次返回的单例实际上并不是同一个。
6.懒汉模式DCL(推荐)
优点:解决了只有在使用时才进行实例化单例,线程安全,需要注意的是成员变量singleton必须加volatile关键字,防止指令重排序。
缺点:可通过反射和反序列化进行更改。
7.静态内部类(推荐)
优点:解决了只有在使用时才进行实例化单例,线程安全,这种方式跟饿汉式方式采用的机制类似,但又有不同。两者都是采用了类装载的机制来保证初始化实例时只有一个线程。不同的地方在饿汉式方式是只要Singleton类被装载就会实例化,而静态内部类的是调用getInstance时才会加载。
缺点:可通过反射和反序列化进行更改。
8.枚举单例(推荐)
枚举单例是出自Effective Java的作者,利用JDK枚举的特性进行实现的。
优点:解决了只有在使用时才进行实例化单例,线程安全,同时不能够被反序列化,以及利用反射进行破坏。
缺点:确实没什么缺点,唯一的缺点就是看着有点奇怪~