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 但此时对象没有完全完成初始化,此时进行使用发生一些不可估的错误。
网友评论