本文内容:什么是单例模式,单例的作用,饿汉模式,懒汉模式的安全与非安全的实现,饿汉模式与懒汉模式的区别.
什么是单例模式?
单例模式:保证一个类,仅有一个实例。提供一个访问它的全局访问点。
单例的作用?
让某个类,仅有一个实例对象。
为什么Retrofit要使用单例模式?
倘若不做单例,它会产生多个对象,反复实例化造成资源浪费。就App来说,一个App里有多少个网络请求,80%几乎需要调用同一个Retrofit对象,大量的实例化操作,这光是想一想都足以让人虎躯一震了。也就是说,如果只是两三个的对象使用,Retrofit没必要使用单例。
饿汉模式是什么?
饿汉模式:是无论你用不用这个对象,在类加载的时候就已经把这个对象实例化好了。
Java实现方式
public class HungrySingle {
//类加载时就进行实例化对象。
private static HungrySingle hungrySingle=new HungrySingle();
//设为private,不让外部代码对其进行new实例化对象。
private HungrySingle() {
}
public static HungrySingle getInstance(){
return hungrySingle;
}
}
kotlin实现方式:
object HungrySingle
相信你已经被kotlin实现单例(饿汉模式)的简洁度吓到,再次感叹kt大法好。
懒汉模式是什么?
懒汉模式: 需要用这个对象的时候,才会去实例化该对象。
Java实现
public class LazySingleJava {
private static LazySingleJava lazySingleJava;
public LazySingleJava() {}
public static LazySingleJava getInstance(){
if (lazySingleJava==null){
lazySingleJava=new LazySingleJava();
}
return lazySingleJava;
}
}
kotlin实现
Tips:
- 这里注意不要用return lazySingle!! 代码,它代表肯定不为空。如果lazySingle真的为空,这样写则会抛异常,导致程序crash;
- 用LazySingle?则让kotlin做了处理,就算为空也不会crash掉程序。
class LazySingle private constructor(){
companion object{
private var lazySingle:LazySingle?=null
get(){
if(lazySingle==null){
lazySingle=LazySingle()
}
return lazySingle
}
fun getInstane(): LazySingle? {
return lazySingle
}
}
}
‘安全’的懒汉模式(线程安全)
情景描述:线程A调用全局访问点getInstance( ),这是对象为null,这时线程A莫名阻塞了。这是我们线程B又去调用全局访问点getInstance( ),这时对象仍然为null,它去创建了新的对象,这时线程A又运行,又去创建了一个对象。
结果:这时所谓的‘单例’则创建了多个对象,违反了我们的单例模式。
安全的懒汉模式
缺点:因在全局访问点上加了同步锁,速度慢;无论是否已有实例化对象,都会走一次锁。
- Java实现
public class LazySingleJava {
private static LazySingleJava lazySingleJava;
public LazySingleJava() { }
//这里增加同步锁synchronized,保证同一时间,只有一个线程来操作它。
public static synchronized LazySingleJava getInstance(){
if (lazySingleJava==null){
lazySingleJava=new LazySingleJava();
}
return lazySingleJava;
}
}
- kotlin实现
class LazySingle private constructor(){
companion object{
private var lazySingle:LazySingle?=null
get(){
if(lazySingle==null){
lazySingle=LazySingle()
}
return lazySingle
}
//增加@Synchronized注解
@Synchronized
fun getInstane(): LazySingle? {
return lazySingle
}
}
}
安全且高效的懒汉模式(双重校验锁)
优点:速度提升;若实例已存在,则不存在违反单例设计的问题,可以直接获取对象,减少因为加锁造成的速度问题。
- Java实现
public class LazySingleJava {
private static LazySingleJava lazySingleJava;
public LazySingleJava() { }
public static LazySingleJava getInstance(){
if (lazySingleJava==null){
//将 synchronized 放置于这里
synchronized(LazySingleJava.class){
lazySingleJava=new LazySingleJava();
}
}
return lazySingleJava;
}
}
- kotlin实现
class LazySingle private constructor(){
companion object{
val instance:LazySingle by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED){
LazySingle()
}
}
}
饿汉模式与懒汉模式的安全以及性能的区别?
线程安全
- 饿汉模式在线程还未出现的时候就已经实例化了,所以饿汉是线程安全的。
效率
- 饿汉模式没有加任何的锁,执行效率高于懒汉模式。
内存
- 饿汉模式在类加载时就实例化了,不管是否调用。相对来说,饿汉会消耗内存一些。