博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
设计模式之单例模式
阅读量:6941 次
发布时间:2019-06-27

本文共 2825 字,大约阅读时间需要 9 分钟。

设计模式之单例模式


一、基础单例模式

     基础单例模式。不考虑多线程的情况下的标准单例模式。

     多线程的情况:假设有N个线程同时访问、A线程走完判断singleton为空而还没有New时、线程B也走完了判断、这时会产生多个Singleton实例

public class Singleton {
//普通的单利模式实现 private Singleton(){}//私有化构造器、防止外部调用new Singleton private static Singleton singleton; public static Singleton getInstance(){ if(singleton==null){
//判断是否存在实例 singleton=new Singleton(); } return singleton; } }

二、改进版支持多线程单例模式

     基础单例模式线程不安全、那么给getInstance()方法增加一个Synchronized吧。

public class UnpreparedSingleton {
// private UnpreparedSingleton(){}//私有化构造器、防止外部调用new Singleton private static UnpreparedSingleton unpreparedSingleton; public synchronized static UnpreparedSingleton getInstance(){
//不好 if(unpreparedSingleton==null){
//判断是否存在实例 unpreparedSingleton=new UnpreparedSingleton(); } return unpreparedSingleton; }}

    大神指出此做法十分愚蠢。因为所有线程均会等待上一个线程执行完getInstance()方法、造成不讲道理的等待。

三、真·改进版支持多线程单例模式

    此写法弥补了上一个版本的不足、直接上代码。

public class NormalSingleton {    private NormalSingleton(){}//私有化构造器、防止外部调用new Singleton    private static NormalSingleton normalSingleton;    public static NormalSingleton getInstance(){        if(normalSingleton==null){            synchronized(NormalSingleton.class){                if(normalSingleton==null){
//判断是否存在实例 normalSingleton=new NormalSingleton(); } } } return normalSingleton; }}

     注:如果不加第二层非空判断会造成当A线程调用完毕返回实例、B线程进入同步块。如果不加判断则会直接执行new Singleton。导致多个实例的出现

    大神说一般情况下此方法是可以了但是还是有特殊情况、原话是:*&……&*…*&&*&%¥%¥%¥%¥¥%#¥%%¥#%¥#¥%

     这才是原话:经过刚才的分析,貌似上述双重加锁的示例看起来是没有问题了,但如果再进一步深入考虑的话,其实仍然是有问题的。

              如果我们深入到JVM中去探索上面这段代码,它就有可能(注意,只是有可能)是有问题的。

              因为虚拟机在执行创建实例的这一步操作的时候,其实是分了好几步去进行的,也就是说创建一个新的对象并非是原子性操作。在有些JVM中上述做法是没有问题的,但是有些情况下是会造成莫名的           错误。

              首先要明白在JVM创建新的对象时,主要要经过三步。

              1.分配内存

              2.初始化构造器

              3.将对象指向分配的内存的地址

              这种顺序在上述双重加锁的方式是没有问题的,因为这种情况下JVM是完成了整个对象的构造才将内存的地址交给了对象。但是如果2和3步骤是相反的(2和3可能是相反的是因为JVM会针对字节码进        行调优,而其中的一项调优便是调整指令的执行顺序),就会出现问题了。

              因为这时将会先将内存地址赋给对象,针对上述的双重加锁,就是说先将分配好的内存地址指给synchronizedSingleton,然后再进行初始化构造器,这时候后面的线程去请求getInstance方法时,会认        为synchronizedSingleton对象已经实例化了,直接返回一个引用。如果在初始化构造器之前,这个线程使用了synchronizedSingleton,就会产生莫名的错误。(看不懂吧 -_-!)

四、终极完整版

  据说这是比较标准的单例模式。

public class BestSingleton {    private BestSingleton(){}//私有化构造器、防止外部new    public static BestSingleton getInstance(){        return BestSingletonSon.bestSingleton;    }    private static class BestSingletonSon{
//内部类 protected static BestSingleton bestSingleton=new BestSingleton(); }}

  JVM在加载类的时候、先创建了静态内部类和其中的变量然后执行外部getInstance()方法、在getInstance()方法中、BestSingletonSon.bestSingleton反回了已经生成的对象的引用而不会去运行New了 保证了单例。

             1.Singleton最多只有一个实例,在不考虑反射强行突破访问限制的情况下。

             2.保证了并发访问的情况下,不会发生由于并发而产生多个实例。

             3.保证了并发访问的情况下,不会由于初始化动作未完全完成而造成使用了尚未正确初始化的实例。

 

转载于:https://www.cnblogs.com/loveyejinhui/p/7599452.html

你可能感兴趣的文章
JQuery上传插件Uploadify使用详解
查看>>
重构第26天 移除双重否定(Remove Double Negative)
查看>>
均值、方差、标准差及协方差、协方差矩阵详解
查看>>
oracle 清除当前用户的回收站
查看>>
有些事必须去做——写在离职之后创业之前
查看>>
转python调用Go代码
查看>>
红黑树(一)之原理和算法的详细分析【转】
查看>>
undefined reference to typeinfo - C++ error message
查看>>
springmvc: 普通list数据输出json
查看>>
8127 timeout!!! 搞死人啊
查看>>
Android开发 设置开机自动启动
查看>>
高德地图iOS SDK限制地图的缩放比例
查看>>
【组件化开发】前端进阶篇之如何编写可维护可升级的代码
查看>>
Node.js node主文件找不到时报出的Error:Cannot find module异常
查看>>
让SQL Server Compact支持 Membership, Role and Profile provider
查看>>
一个编译器的实现2——从文法到LL(1)分析表的概念和算法
查看>>
报表系统结构优化之中间数据外置
查看>>
《JAVA与模式》之门面模式
查看>>
vim/vi的文件内、跨文件复制粘贴操作、替换操作
查看>>
java命令执行jar文件
查看>>