单例的使用一般分为三步:
(1)最简单的一种方式
<span style="white-space:pre"> </span>private static AudioManager mInstance; //第一步:一个私有静态的类成员变量 private AudioManager() {} //第二步:一个私有的构造方法 public static AudioManager getInstance() {//第三步:一个public的对外获取实例的方法 <span style="white-space:pre"> </span>if (mInstance == null) { mInstance = new AudioManager(); } return mInstance; }
这种方式只有在单线程的时候工作正常,设想在多线程的情况下,当两个线程同时运行到判断mInstance是否为null的if语句,并且mInstance没有创建时,这时两个线程都回去创建一个实例,此时就不符合单例的要求了。
(2)能在多线程下工作但线率不高的方式
由(1)可知,为了让其能在多线程下正常工作,需要加上一把同步锁,修改如下:
<span style="white-space:pre"> </span><span style="font-size:18px;">private static AudioManager mInstance; //第一步:一个私有静态的类成员变量 private AudioManager() {} //第二步:一个私有的构造方法 public static AudioManager getInstance() {//第三步:一个public的对外获取实例的方法 synchronized (AudioManager.class) { <span style="white-space:pre"> </span>if (mInstance == null) { <span style="white-space:pre"> </span>mInstance = new AudioManager(); } } return mInstance; }</span>
通过这种加同步锁的方式,我们可以保证在多线程的环境下只得到一个该类的实例,但我们每次通过getInstance()方法去取实例时,都会试图加上一个同步锁,而加锁是一个非常耗时的操作,在该实例存在时我们就应该尽量避免再去加锁。
(3)推荐使用的方式
<span style="font-size: 18px; "><span style="white-space:pre"> </span>/** * 通过单例实现获取本类(AudioManager)对象 */ private static AudioManager mInstance; //第一步:一个私有静态的类成员变量 private AudioManager() {} //第二步:一个私有的构造方法 public static AudioManager getInstance() {//第三步:一个public的对外获取实例的方法 if (mInstance == null) { synchronized (AudioManager.class) { if (mInstance == null) { mInstance = new AudioManager(); } } } return mInstance; }</span>
如果获取实例时需要给构造方法传入参数,直接在getInstance()里面加入参数即可,如:
<span style="font-size:18px;"><span style="white-space:pre"> </span>private String mDir;</span>
<span style="font-size:18px;"><span style="white-space:pre"> </span>private static AudioManager mInstance;//第一步:一个私有静态的类成员变量 private AudioManager(String dir) {//第二步:一个私有的构造方法 mDir = dir; } public static AudioManager getInstance(String dir) {//第三步:一个public的对外获取实例的方法 if (mInstance == null) { synchronized (AudioManager.class) { if (mInstance == null) { mInstance = new AudioManager(dir); } } } return mInstance; }</span>
上面的getInstance方法里面通过两次 if 判断,控制只有当mInstance为null即没有创建时,才需要加锁操作。因为只在第一次的时候mInstance为null,因此只有在第一次试图创建实例的时候才需要加锁,相对于第二种方式效率会有很大的提高。
时间: 2024-10-19 21:09:45