单例模式:
原理:私有化构造方法,通过静态方法获取一个唯一的实例。(获取过程中必须保证线程安全、防止反序列化导致重新生成对象等问题。)
饿汉式:
public class SingleTon {
//在类初始化时直接new对象
private static SingleTon instance = new SingleTon();
private SingleTon(){}
public static SingleTon getInstance(){
return instance;
}
}
懒汉式:
public class SingleTon {
private static SingleTon instance;
private SingleTon(){}
//同步方法获取唯一实例。缺点:每次getInstance时都会同步,浪费资源。
public static synchronized SingleTon getInstance(){
//判断对象是否存在
if (instance == null){
instance = new SingleTon();
}
return instance;
}
//去掉synchronized。缺点:不能保证单例的唯一性。(但android中并发情况少)
public static SingleTon getInstance(){
if (instance == null){
instance = new SingleTon();
}
return instance;
}
}
Double Check Lock(DCL双重判断校验):
public class SingleTon {
private static SingleTon instance;
private SingleTon() {}
public static SingleTon getInstance() {
if (instance == null) {
synchronized (SingleTon.class) {
if (instance == null) {
instance = new SingleTon();
}
}
}
return instance;
}
}
/**
* DCL失效:
*
* SingleTon instance = new SingleTon() 这句代码最终会编译成多条汇编指令。
* 大致做了3件事:
* 1、给SingleTon的实例分配内存;
* 2、调用SingleTon()的构造函数,初始化成员字段;
* 3、将instance对象指向分配的内存空间(此时instance就不再是null)
* 但是,由于Java编译器允许处理器乱序执行,以及JDK1.5之前JMM(Java Memory Model,即Java内存模型)
* 中的Cache、寄存器到主内存回写顺序的规定,上面的第二和第三顺序无法保证。
* 也就是说,执行顺序可能是1-2-3,也可能是1-3-2。
* 如果是1-3-2顺序执行,就可能出现如下情况:
* 程序执行到3完毕,2还没来得及执行,CPU资源切换到线程B,由于instance已经不是null了,
* 所以线程B会直接取走instance,而上面的步骤2将不会得到执行。
* 在使用时就会出错,就就是DCL失效问题。
* 而且这种难以追踪难以重现的问题可能会隐藏很久。
*
*
* 在JDK1.5之后,调整了JVM,具体化了volatile关键字。
* 因此JDK1.5之后的版本,只需要将instance的定义改成
* private volatile static SingleTon instance = null
* 就可以保证对象每次都是从主内存中读取,
* DCL失效问题解决。
*
* 不足:volatile或多或少会影响到性能
*
* DCL的优点:资源利用率高,效率高。绝大多数场景下能保证单例对象的唯一性。
* 缺点:第一次加载反应稍慢,小概率由于java内存模型原因失败。
*/
静态单例:
//推荐使用
public class SingleTon {
private SingleTon(){}
public static SingleTon getInstance(){
return SingletonHolder.instance;
}
/**
* 静态内部类
*
* 既保证了线程安全,又保证了对象的唯一性
*/
private static class SingletonHolder{
private static final SingleTon instance = new SingleTon();
}
}
枚举单例:
//枚举比static占内存多很多
public enum SingleTon {
INSTANCE
}
容器单例:
public class SingletonManager {
private static Map<String, Object> objMap = new HashMap<>();
private SingletonManager(){}
public static void registerService(String key, Object instance){
if (!objMap.containsKey(key)){
objMap.put(key, instance);
}
}
public static Object getService(String key){
return objMap.get(key);
}
}
&&
Android Studio 可直接创建单例,以上内容,可权当了解。