玩转Java设计模式之单例模式一
什么是单例模式
单例模式简单来说,就是要保证一个类在进程内有且只有一个实例对象。这个类对外提供了唯一获取其实例对象的静态方法,且构造方法私有化。
单例模式实现方式
- 懒汉式(4种)
- 饿汉式(2种)
- 静态内部类(1种)
- 枚举(1种)
懒汉式实现方式一
缺点:并发场景时,线程不安全。
结论:不推荐使用。
public class SingletonDemo3 {
//直接初始化对象
private static SingletonDemo3 instance;
//构造方法私有化
private SingletonDemo3(){}
//
public static SingletonDemo3 getInstance( ){
if(instance==null){
instance = new SingletonDemo3();
}
return instance;
}
}
懒汉式实现方式二
针对实现方式一来进行升级,加入线程同步锁synchronized,保证线程安全。
缺点:由于synchronized加在了方法上,并发场景下都要获取锁,性能较差。
结论:不推荐使用。
public class SingletonDemo4 {
//直接初始化对象
private static SingletonDemo4 instance;
//构造方法私有化
private SingletonDemo4(){}
//
public static synchronized SingletonDemo4 getInstance( ){
if(instance==null){
instance = new SingletonDemo4();
}
return instance;
}
}
懒汉式实现方式三(双重检查+同步锁)
针对实现方式二进行升级,将synchronized放在方法代码块中,保证并发性能。
这种实现方式就完美了吗?NO!!!
缺点:由于java 虚拟机会对class进行指令重排序(JVM在保证最终结果正确的情况下,
可以不按照程序编码的顺序执行语句,尽可能提高程序的性能),在JVM中初始化对象分为三步:
1.为初始化对象分配内存空间;
2.初始化实例对象;
3.将初始化对象指定分配好的内存空间。
在发生指令重排序后,执行顺序为:1->3->2 。并发场景下,可能线程1创建单例时执行了1->3,线程2发现单例已创建,其实得到的是未初始化完成的对象,导致NPE异常。
结论:不推荐使用。
public class SingletonDemo5 {
//直接初始化对象
private static SingletonDemo5 instance;
//构造方法私有化
private SingletonDemo5(){}
//
public static SingletonDemo5 getInstance( ){
if(instance==null){
synchronized (SingletonDemo5.class){
instance = new SingletonDemo5();
}
}
return instance;
}
}
懒汉式实现方式四(双重检查+同步锁+volatile)
针对实现方式三存在的问题进行升级,在单例对象变量前加入volatile关键字修饰,防止指令重排序。
结论:推荐使用。
public class SingletonDemo6 {
//直接初始化对象
private static volatile SingletonDemo6 instance;
//构造方法私有化
private SingletonDemo6(){}
//
public static SingletonDemo6 getInstance( ){
if(instance==null){
synchronized (SingletonDemo6.class){
if(instance == null){
instance = new SingletonDemo6();
}
}
}
return instance;
}
}
由于考虑篇幅较长,本章节仅分享懒汉式的4种实现方式,并分析其优缺点,最后给出推荐使用的懒汉式实现方式。下一章节将分享单例模式的饿汉式、静态内部类、枚举实现方式。
如本文使你受益,请给予点赞、关注、收藏、转发,鼓励小编继续创作。
如有错误或不妥之处,欢迎拍砖!!!
上一篇:设计模式之单例模式