android学习-10 单例模式

单例模式分为大致两种,饿汉模式和懒汉模式。

一、饿汉模式

系统一运行就创建对象,不考虑太多的问题,所以可能会被创建多次,存在多个对象。但是明显会有浪费内存。线程安全

public class Singleton{
    //类加载时就初始化
    private static final Singleton instance = new Singleton();
    
    private Singleton(){}

    public static Singleton getInstance(){
        return instance;
    }
}

二、懒汉模式

当获取实例时才去创建,但是是线程不安全的。

public class Singleton2 {
 
	private static Singleton2 singleton;
	
	private Singleton2(){
		
	}
	
	public static synchronized Singleton2 getInstance(){
		if(singleton == null) 
			singleton = new Singleton2();
		return singleton;
	}
}

三、懒汉模式的双层锁模式

public class Singleton3 {
	private volatile  static Singleton3 singleton;//1
	
	private Singleton3(){
		
	}
	
	public static Singleton3 getInstance(){
		if(singleton == null){ //2
			synchronized(Singleton3.class){ //3
				if(singleton == null){ //4
					singleton = new Singleton3();
				}
			}
		}
		return singleton;
	}
}

大致可分为2块地方,1,234

1、第1步

因为singleton = new Singleton3(); 本质上是非原子性操作的,实际上在JVM里大概做了3件事。

1.给singleton分配内存

2.调用Singleton3构造完成初始化

3.使singleton对象的引用指向分配的内存空间(完成这一步singleton就不是null了)

但是在 JVM 的即时编译器中存在指令重排序的优化.也就是说上面的第二步和第三步的顺序是不能保证的,最终的执行顺序可能是 1-2-3 也可能是 1-3-2.如果是后者,则在 3 执行完毕、2 未执行之前,被线程二抢占了,这时 singleton已经是非 null 了(但却没有初始化),所以线程二会直接返回 singleton,然后使用,然后报错.

注意:volatile阻止的不是singleton = new Singleton()这句话内部[1-2-3]的指令重排,而是保证了在一个写操作([1-2-3])完成之前,不会调用读操作(if (instance == null))。

2、第234步

内层判断:防止实例化多次
外层判断:试图想想一种情况,当线程1走完了内层判断,对象实例化了,线程3也调用了getInstace函数,如果没有加外层的判断线程3还是要继续等待线程2的完成,而加上外层判断,就不需要等待了,直接返回了实例化的对象。

四、懒汉模式的内存泄漏

在android中,有时会将一个activity作为单例模式来使用,这样会出现以下写法

  public class Singleton3 {
    	private volatile  static Singleton3 singleton;//1
    	
    	private Singleton3(){
    		 this.mContext = mContext;
    	}
    	
    	public static Singleton3 getInstance(){
    		if(singleton == null){ //2
    			synchronized(Singleton3.class){ //3
    				if(singleton == null){ //4
    					singleton = new Singleton3(context);
    				}
    			}
    		}
    		return singleton;
    	}
    }

其中context通常传入的是activity、Service等上下文,这会导致内存泄漏。
因为我们退出Activity时,该Activity就没有用了,但是因为singleton作为静态单例(在应用程序的整个生命周期中存在)会继续持有这个Activity的引用,导致这个Activity对象无法被回收释放,就造成了内存泄漏。
修改方法是,将context参数改为全局的上下文:

private Singleton3(){
        		 this.mContext =mContext.getApplicationContext();
        	}

参考:
https://blog.youkuaiyun.com/Imobama/article/details/81093394

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值