第一种:懒汉
调用判断为空时才去创建实例,缺点:线程不安全容易造成死锁,个人不推荐这种方式实现
1 | public class Singleton { |
第二种:懒汉 加同步锁
为解决第一种方式线程不安全的问题加入了同步锁; 但是每次获取实例都需要加锁, 不推荐
优点:线程安全不用担心多线程调用, 缺点:大多数情况不需要同步,效率低
1 | public class Singleton2 { |
第三种: 饿汉
这种方式基于classloder加载机制避免了多线程的同步问题, 但是内存中始终存在一个我们有可能不用的实例对象,很浪费
1 | public class Singleton |
第四种: 饿汉 变种
用static代码块来加载对象,但JVM加载类时会执行这些静态的代码块,同样没有达到lazy loading的效果,其优缺点和第三种一样
1 | public class Singleton { |
第五种:静态内部类
同样基于classloder加载机制,解决了懒汉式中多线程的问题.并且当只有我们调用了getInstance()获取实例时,才会创建唯一的实例到内存中也实现了延迟加载。
1 | public class Singleton { |
第六种: 枚举
优点:线程安全, 防止反序列化重新创建新的对象
Java1.5才出现enum特性,使用时注意
1 | public enum Singleton { |
第七种: 双重校验模式
最常用的一种
加入同步锁避免多线程调用的问题;提前判断实例对象避免每次进入同步锁(这样只是在初始化对象的时候执行同步锁)
1 | public class Singleton { |
注意
以上除第六种枚举外其他如果Singleton实现了java.io.Serializable接口,那么这个类的实例就可能被序列化和复原。如果你序列化一个单例类的对象,接下来复原多个那个对象,那你就会产生多个单例类的实例
这种情况解决:
1 | public class Singleton implements java.io.Serializable { |