DCL机制下的隐患?

2023-06-06  本文已影响0人  发疯的2魅

dcl : double check lock 双重检查锁机制

       脱胎于单例模式,饿汉式单例模式 

        饿汉式单例模式

        class  RetrofitUrl {

                fun getInstance():RetrofitUrl {

                            if (retrofitService == null) {

                                    synchronized(RetrofitUrl::class.java){

                                           val interceptor = HttpLoggingInterceptor()

                                           interceptor.level = HttpLoggingInterceptor.Level.BODY

                                           val client = OkHttpClient.Builder()

                                           .connectTimeout(60,TimeUnit.SECONDS)

                                           .readTimeout(60,TimeUnit.SECONDS)

                                            .writeTimeout(60,TimeUnit.SECONDS)

                                             .addInterceptor(interceptor)

                                              .retryOnConnectionFailure(true)

                                               .build()

                                    val retrofit = Retrofit.Builder()//设置数据解析器

                                            .addConverterFactory(GsonConverterFactory.create())

                                            .addCallAdapterFactory(RxJavaCallAdapterFactory.create())

                                            .client(client)//设置网络请求的Url地址

                                            .baseUrl(getBase())

                                            .build()// 创建网络请求接口的实例

                                            retrofitService = retrofit.create(RetrofitUrl::class.java)

                        }

                }

                        return retrofitService!!

                    }

        }

   传统单例模式 在上版本基础上去掉了  synchronized(RetrofitUrl::class.java) 锁,旨在解决单线程情况下单一实例问题,多线程访问会导致

    创建多个实例问题。

    多线程每个线程拥有一块内存,此内存对该线程开放,其他线程无法访问其中变量 (volatile修饰除外<此关键字修饰内容会主动把线程内变量同步到主内存,也就是全部线程可访问>)  ,而加入锁之后会同步所有线程。

   但上述模式在某些特殊情况下会发生错误,根源在于cpu 指令重排序

          因为上述中创建对象  例如  sigton = new  sington() 这个操作不是原子性的,发生是需要几个步骤和过程

           其中分为三步

            1. 给创建的对象分配内存空间

             2. 初始化创建的对象

             3. 将内存地址指针赋予生成的对象 

            按照上述步骤依次完成生成的对象此时不再为空,引用可进行调用

            而特殊情况就发生在2和3 的步骤上,发生重排序后,若顺序变为 1-3-2,多线程访问有可能2没有完成,也就是此时对象不为null 但此时对象没有完全完成初始化,此时进行使用发生一些不可估的错误。

   

上一篇下一篇

猜你喜欢

热点阅读