单例的理解
hi, 大家好,我是爱吃香蕉的猴子,今天看到郭神之前的一篇文章膜拜,关于使用单例的,自己有些感触,就借鉴写一下记录.
延续大神的例子:
第一版
不使用单例,new的太多,占用内存,不可取;
第二版
public class LogUtil {
private static LogUtil sLogUtil;
public static LogUtil getInstance() {
//1
if (sLogUtil == null) { //2
//3
sLogUtil = new LogUtil(); //4
}
/ /5
return sLogUtil;
}
}
LogUtil.getInstance().debug("Hello World");
这种方式,如果在多线程模式下,如果thead B、thread A, 在3位置 这样,thread A初始化了,thread B也会初始化,这样也会出现两个实例,则需要增加锁。
第三版
private static LogUtil sLogUtil;
public synchronized static LogUtil getInstance() {
if (sLogUtil == null) {
sLogUtil = new LogUtil();
}
return sLogUtil;
}
在方法上加上synchronized,线程排队执行,每次执行getInstance都要受锁影响,这样效率相对低一些;
第四版
private static LogUtil sLogUtil;
public static LogUtil getInstance() {
synchronized (LogUtil.class) {
if (sLogUtil == null) {
sLogUtil = new LogUtil();
}
return sLogUtil;
}
}```
在方法内增加类锁,但是:如果theadA threadB都在锁外,已经初始化的也在排队,是否可以增加判断;
*第五版*
private static LogUtil sLogUtil;
public static LogUtil getInstance() {
if (sLogUtil == null) {
//没有初始化的排队
synchronized (LogUtil.class) {
if (sLogUtil == null) {
sLogUtil = new LogUtil();
}
}
}
return sLogUtil;
这样,代码改成这样之后,基本完善了,但是在线程A中sLogUtil实例化了,在线程B中是可见的吗?
第六版
private volatile static LogUtil sLogUtil;
public static LogUtil getInstance() {
/ /0
if (sLogUtil == null) { // 1
//2
synchronized (LogUtil.class) { // 3
//4
if (sLogUtil == null) { // 5
//6
sLogUtil = new LogUtil(); //7
}
}
}
return sLogUtil;
}
增加了Volatile [ˈvɒlətaɪl] ,这样线程间可见;
这样,算是完整了。
有人问我,为什么5还要加一次判断?
我是这样认为的,在ThreadA 执行了7,这个时候,TheadB执行到3进入4,这种场景,自然就需要增加一次判断;
还有人提出过,为什么不用枚举,这个方案虽然是java里面被推荐的,但 个人认为不适合android, 因为枚举还是站用内存较大的。
为什么枚举占内存大
Code的搬运工V1.o