Android单例模式 Double -Check 写法

Android设计模式

单例模式

单例模式的概念:确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。
优点:

  • 对于那些比较耗内存的类,只实例化一次可以大大提高性能,尤其是在移动开发中。
  • 保持程序运行的时候该中始终只有一个实例存在内存中

单例有很多写法 如:饿汉式, 懒汉式 , 双重校验锁, 静态内部类写法等 ,这里我们介绍的是双重校验锁的写法

单例模式 - Double Check


//java写法
public class SingleDemo{
private volatile static SingleDemo instance;
private SingleDemo (){}
public static SingleDemo getInstance(){
	if(instance==null){
		synchronized (SingleDemo.class){
			if(instance==null){
		instance=new SingleDemo();
							}
						}
					}
					return instance;
				} 	
		}

保证为单例需要做的几个点:

  • 必须防止外部可以调用构造函数进行实例化,因此构造函数必须私有化。
  • 必须定义一个静态函数获得该单例
  • 单例使用volatile修饰
  • 使用synchronized 进行同步处理,并且双重判断是否为null,我们看到synchronized (Singleton.class)里面又进行了是否为null的判断,这是因为一个线程进入了该代码,如果另一个线程在等待,这时候前一个线程创建了一个实例出来完毕后,另一个线程获得锁进入该同步代码,实例已经存在,没必要再次创建,因此这个判断是否是null还是必须的。

为什么单例需要用volatile来修饰

因为如果不使用volatile来修饰的话可能会出现一种报null的异常
现在我们来分析一下为什么会出现这种异常
代码块中有一行代码:instance = new SingleTon();
其实在底层这行代码是分三个步骤来进行的
1.分配地址空间
2.初始化SingleDemo对象
3.将SingleDemo对象的地址赋值给instance (此时instance不为null)
但是由于JVM为了提高性能,编译器和处理器都会对指令进行重排,由于上述的2,3步没有数据依赖,可以进行重排。所以指令执行的顺序可能会变成1->3->2 如果出现这种情况时而又恰好在执行3 的时候另一个线程过来判断instance不为null 直接调用单例内部的方法的话就会报null,所以在使用Double Check 创建单例时需要使用volatile来修饰。

Kotlin写法

class SingletonDemo private constructor() {
    companion object {
        val instance: SingletonDemo by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) {
        SingletonDemo() }
    }
}

或者直接将创建类型设置为Object

object SingleDemo{
}

嗯 没错!Kotlin就是这么简单又充实

参考文档:
Kotlin下的5种单例模式
Android开发中常见的设计模式
单例模式的六种实现方式及可能遇到的问题

你可能感兴趣的:(android)