既然来了简书,总要留下点什么.......
读书养才气,勤奋养运气,宽厚养大气,淡泊养志气
1-What
保证一个类在任何情况下在程序中都绝对只有一个实例,并且提供一个全局访问点。
2-Premise
1.构造函数私有,防止被外部new对象;
2.内部必须提供一个静态的方法,让外部调用。
3-Advantage
减少内存开销;
避免资源多重占用。
4-Disadvantage
不易扩展。
5-Classify
5-1-饿汉式
类加载过程中,就已经创建了实例。
public class SingletonE {
//静态修饰的实例,类在加载时就是执行实例化操作
private static SingletonE mInstance = new SingletonE();
//构造函数私有化,使外界无法创建实例
private SingletonE(){
}
//为外界提供获取实例的方法
public static SingletonE getInstance(){
return mInstance;
}
}
也可以通过静态代码块方法初始化。
不足:浪费内存空间;代码不灵活。
5-2-懒汉式
当需要使用类的时候,才去实例化。
public class SingletonL {
private static SingletonL mInstance;
private SingletonL(){}
public static SingletonL getInstance(){
if (mInstance == null){ //null判断
mInstance = new SingletonL();
}
return mInstance;
}
}
不足:多线程中不能保证只创建一次实例。(多线程并发)
解决方法:加锁——synchronized
public synchronized static SingletonL getInstance(){
if (mInstance == null){ //null判断
mInstance = new SingletonL();
}
return mInstance;
}
不足:虽然解决了线程安全的问题,但是方法每次调用的时候,都会进行同步检查,造成效率低。
解决方法:双重检查锁——减少同步检查范围
public static SingletonL getInstance(){
if (mInstance == null){
synchronized (SingletonL.class){ //同步检查
if (mInstance == null){
mInstance = new SingletonL();
}
}
}
return mInstance;
}
不足:mInstance可能未初始化,用户获取的对象是空的
原因:Java虚拟机的指令:
1.给对象分配内存;
2.调用方法初始化对象;
3.将对象与内存关联,赋值。
但是Java多线程中,步骤2和3的执行顺序不是固定的。
解决方法:volatile的使用 1.防止重排序;2.保证对象可见性。某一线程改了变量,短时间内该变量在另一个线程可能是不可见的,因为每一个线程都有自己的缓存区。
private static volatile SingletonL mInstance;
5-3-静态内部类
public class SingletonS {
private SingletonS(){
}
public static SingletonS getInstance(){
return SingletonHolder.mInstance;
}
public static class SingletonHolder{
private static SingletonS mInstance = new SingletonS();
}
}
好处:既保证线程安全,又实现了懒加载。
5-4-静态代码块结合容器(HashMap)
private static Map<String,Object> map = new HashMap<>();
static {
map.put("single",new SingletonS());
}
除了上述的几种方式外,枚举也能实现单例,而且是最简单的,但是也存在一种问题——代码不灵活。所以,究竟选择哪一种方式实现单例,还是根据开发者自己以及项目需求。
6-Where
Activity管理
参考文章:
https://segmentfault.com/a/1190000018494382
https://blog.csdn.net/qq_25333681/article/details/93662660