单例模式
官方定义
确保一个类只有一个实例,而且自行实例化并向整个系统提供这个实例
实例代码
定义知道了,但是定义中说确保只有一个实例,这个如何确保呢?
一般来说,一个类创建一个对象需要使用new关键字,此时,我们需要把构造函数设置为private,禁止外部通过构造函数new出一个对象。既然在外部通过构造函数不行了,那么就得有其他的办法,看代码
public class SingleInstance {
private static final SingleInstance singleInstance = new SingleInstance();
private SingleInstance() {
}
public static SingleInstance getInstance() {
return singleInstance;
}
}
这就是大名鼎鼎的饿汉模式了,通过使用private的构造函数确保了在一个应用中只产生一个实例,并且是自行实例化的(在SingleInstance 中自己使用new SingleInstance ())
如果各位小伙伴想偷懒的话,可以试试Kotlin,Kotlin中的单例是这么写的
object SingleInstance
对,就是两个单词。
单例模式的优势
因为只创建了一个实例,所以内存的开销较小,如果有对象涉及到频繁的创建和销毁的时候,适合使用单例模式,比如Retrofit的使用,文件读写。
单例模式的缺点
扩展困难,一般只能通过修改代码进行扩展
单例的线程安全问题
看如下代码
public class SingleInstance {
private static SingleInstance singleInstance = null;
private SingleInstance() {
}
public static SingleInstance getInstance() {
if (singleInstance == null) {
singleInstance = new SingleInstance();
}
return singleInstance;
}
}
以上是一个典型的线程不安全的实例。
当线程1执行到new SingleInstance()获取对象但是还没有获取到对象的时候,线程2也执行到了这一步,此时singleInstance == null判断为真,也会获取到一个对象,于是,在内存中就出现了两个SingleInstance对象。这种情况在并发量增加的时候很容易出现
一般来说,解决线程安全的问题就是使用同步机制,加上synchronized。也就是
public class SingleInstance {
private static SingleInstance singleInstance = null;
private SingleInstance() {
}
public static synchronized SingleInstance getInstance() {
if (singleInstance == null) {
singleInstance = new SingleInstance();
}
return singleInstance;
}
}
这种模式也称之为懒汉单例。但是这样还是会有问题,就是每次调用getInstance方法的时候就会产生同步开销,于是就有了DLC模式,也就是双重锁机制。
public class SingleInstance {
private static SingleInstance singleInstance = null;
private SingleInstance() {
}
public static SingleInstance getInstance() {
if (singleInstance == null) {
synchronized (SingleInstance.class) {
if (null == singleInstance) {
singleInstance = new SingleInstance();
}
}
}
return singleInstance;
}
}
在判断当前没有实例的时候,才会进行同步操作。