简介
单例模式是指在程序中只有一个实例存在。并且在程序运行中的任何时候都可以获取该实例对象。
场景
1.Android中数据库多线程读写时,保证每个线程使用同一个SQLiteDatabase对象,否则会报错“database is locked”;
2.Android常用框架EventBus中使用了单例模式。例如,当我们获取EventBus对象时,会使用的EventBus.getDefault(),当我们查看它的源码的时候,我们发现
static volatile EventBus defaultInstance;
...//此处省略
...
public static EventBus getDefault() {
if (defaultInstance == null) {
Class var0 = EventBus.class;
synchronized(EventBus.class) {
if (defaultInstance == null) {
defaultInstance = new EventBus();
}
}
}
return defaultInstance;
}
也就是EventBus使用了双重校验锁的单例模式。此模式稍候介绍。
单例模式的实现方式
1.懒汉模式
特点:懒加载,不使用不创建,线程不安全
public class Singleton {
private static Singleton mSingleton = null;
private Singleton() {
}
public static Singleton getInstance() {
if (mSingleton == null)
mSingleton = new Singleton();
return mSingleton;
}
}
2.饿汉模式
特点:类加载的时候就创建对象,线程安全,没有懒加载的灵活性,可能造成内存浪费
public class Singleton {
private static Singleton mSingleton = new Singleton();
private Singleton() {
}
public static Singleton getInstance() {
return mSingleton;
}
}
3.双重校验锁
特点:可以保证线程安全,但是需要使用volatile(JDK1.5引入)修饰对象的引用,因为只是使用双重校验锁时,也不能保证它是一个线程安全的单例模式。因为JMM会有指令重排序机制。当我们创建一个对象的时候,JVM内部会将new Object()这条语句转化为若干指令,举例:
指令1:先为对象分配内存空间
指令2:初始化对象
指令3:设置对象所在的内存地址
以上是正常情况,如果发生了指令重排,可能指令3就会排在指令2的前面。
也就是先分配了内存地址,后初始化的对象。如果这时线程A指令执行的顺序是1-3-2,那么,当线程A执行到指令3的时候,mSingleton不为null了。如果线程B执行到第一个if判断的时候,发现mSingleton不为空,这时就会出现问题。(见下面代码)
public class Singleton {
private static Singleton mSingleton = null;
private Singleton() {
}
public Singleton getInstance() {
if (mSingleton == null) {
synchronized (Singleton.this) {
if (mSingleton == null)
mSingleton = new Singleton();
}
}
return mSingleton;
}
}
使用volatile关键字后,就可以禁止指令重排序(增加了内存屏障)
正确代码:
public class Singleton {
private volatile static Singleton mSingleton = null;
private Singleton() {
}
public Singleton getInstance() {
if (mSingleton == null) {
synchronized (Singleton.this) {
if (mSingleton == null)
mSingleton = new Singleton();
}
}
return mSingleton;
}
}
4.静态内部类
特点:类加载的时候就创建对象(此特点跟饿汉模式一样),线程安全;懒加载,不使用不创建,减少内存开销。
public class Singleton {
private Singleton() {
}
private static class SingleInstance {
private static final Singleton singleton = new Singleton();
}
public static final Singleton getInstance() {
return SingleInstance.singleton;
}
}
5.枚举单例模式
特点:线程安全,防止了反序列化重新创建的新对象
public enum EmumSingleton {
SINGLETON;
EmumSingleton() {
}
public void doSomething(){
System.out.println("单例模式");
}
}
Over…