5种常见的单例模式
Posted atseas
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了5种常见的单例模式相关的知识,希望对你有一定的参考价值。
1.懒汉式(使用时构建对象)
1.1 版本1:直接私有化构造函数。
缺点:非线程安全,当多个线程同时运行到if (instance==null)时,会创建多个对象。
1 public class Singleton { 2 private static Singleton instance; 3 private Singleton(){ 4 5 } 6 public static Singleton getInstance(){ 7 if(instance==null){ 8 instance=new Singleton(); 9 } 10 return instance; 11 } 12 }
1.2 版本2: synchronized版本,使用同步锁。
缺点:造成其他线程全在等待,影响程序执行效率。
1 public class Singleton { 2 private static Singleton instance; 3 private Singleton(){ 4 5 } 6 public static synchronized Singleton getInstance(){ 7 if(instance==null){ 8 instance=new Singleton(); 9 } 10 return instance; 11 } 12 }
2.双重校验锁
优点:减少加锁的代码块,当问题发生时才去处理。
public class Singleton { private static Singleton instance;//1 private Singleton(){ } public static Singleton getInstance(){ if(instance==null){//2 synchronized (Singleton .class) { if (instance == null) {//3 instance = new Singleton ();//4 } } } return instance; } }
注:这段代码在JDK1.5以下会有问题。
假设现在有线程A,和线程B两个线程。
1.线程A进入getInstance方法,走到代码2处,判断为null,进入同步块。
2.线程A走到代码3处,判读为null。
3.线程A走到代码4处,执行new操作,在SingletonDoubleCheck还未实例化完成时,使intance为非null。
4.线程B进入getInc方法,走到代码2处,判读非null,返回。
这时候线程B代码中inatance实例引用的是一个不完整的对象。
原因就在于对象的new操作并不是一个原子性操作,它分为3步:
1,给 instance 分配内存 2,调用 SingletonDoubleCheck 的构造函数来初始化成员变量 3,将SingletonDoubleCheck对象指向分配的内存空间(执行完这步 instance 就为非 null 了)
由于JVM的指令重排序(happen-before)的原因,线程B拿到的是初始化未完成的对象,此时会报错。因此我们在代码1处加上关键字volatile
private static volatile Singleton instance;
注:volatile屏蔽指令重排序的语义在JDK1.5中才被完全修复,此前的JDK中即使将变量声明为volatile也仍然不能完全避免重排序所导致的问题(主要是volatile变量前后的代码仍然存在重排序问题),这点也是在JDK1.5之前的Java中无法安全使用DCL(双锁检测)来实现单例模式的原因。
3.饿汉式(类加载时构造对象)
优点:类装载的过程由类加载器(ClassLoader)执行,JVM保证线程的同步,避免了有多线程引起的问题。
缺点:开发者难以把握初始化时机:
1.加载早会造成资源浪费。
2.如果初始化依赖其他数据,难以保证其他数据在加载前就已准备好。
适用:所需单例占用资源少,不依赖其他数据。
public class Singleton{ private static final Singleton INATANCE =new Singleton(); private Singleton (){ } public static Singleton getInatance(){ return INATANCE; } }
4.静态内部类(延迟加载)
优点:类装载的过程由类加载器(ClassLoader)执行,JVM保证线程的同步,避免了有多线程引起的问题。
在使用时才进行实例化,避免资源的浪费。
public class Singleton { private static class SingletonHolder { private static final Singleton INSTANCE = new Singleton(); } private Singleton (){} public static final Singleton getInstance() { return SingletonHolder.INSTANCE; } }
5.枚举
优点:1.线程安全。2.防止反序列化创建对象。
缺点:不能继承,暂时用的人比较少,不合群。
public Enum Singleton{ INSTANCE; public void Method(){ } }
文章仅供参考,欢迎批评指正。
以上是关于5种常见的单例模式的主要内容,如果未能解决你的问题,请参考以下文章