Android 中的单例模式

单例模式(Singleton)

单例模式是对象的创建模式,单例模式能够确保某个类只有一个单一的实例对象存在,同时能够自行实例化并将单一的实例提供给外界调用的特点,其在实际项目开发中经常被用到。

特点:
1. 单例类(Singleton)只能有一个唯一的实例存在。
2. 单例类必须有能够自行创建自己的实例对象的能力。
3. 单例类必须能够给外界其他对象提供这里实例。

问题1:
首先我们需要来考虑2件事情,既然单例模式需要保证系统中最多只有一个这样的对象事例,那么我怎么才能确保只能有一个实例呢??

构造方法:如果构造方法是 public,那么任何类都可以 new 我的对象,不能保证单例,所以单例模式构造方法一定是 private的
如果构造方法是 private的,那么我怎么 new对象呢?说明我只能在我自己的类中,先new出自己,然后提供给外部。
由于系统只有一个单例对象,那么线程同步是一定需要的,怎么来做呢?

就是因为上面的第2步,我们就出现了很多单例模式的写法,下面我们一一介绍:

饿汉式

public class Singleton {
private static Singleton instance = new Singleton();

private Singleton(){}

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

也可以这么写:

public class Singleton {
private static Singleton instance;

static{
    instance = new Singleton();
}

private Singleton(){}

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

**问题二:
1:为什么 构造方法是 private的? 因为上面提到的,不能由其他类任意new单例模式的类
2:为什么 getInstance() 是 static方法,因为用了 类名.来调用getInstance() 方法。
3:为什么 instance 是 static的? 静态方法可以访问非静态变量吗?显然不行,所以instance也是static的,而且静态变量是不是只会被初始化一次(感觉3个问题都是java考试题一样,哈哈哈!)
4:上面的第二种使用到了静态初始化块,在Singleton第一次被使用的时候初始化。**

懒汉式

public class Singleton {
private static Singleton instance;

private Singleton(){}

public static Singleton getInstance() {
    if(null == instance){
        instance = new Singleton();
    }
    return instance;
} }
结论:与饿汉式的不同:不是一看到 instance 就初始化,懒汉要等到第一次使用的时候才初始化,不像饿汉一样一见到 instance 就初始化,这也被称为 懒加载,如果系统中很多这样的类,显然是懒加载的时候效率更高

线程安全:

如果对线程学得还行的同学就应该知道,上面的饱汉式写法其实不是那么的安全!!虽然在 getInstance() 中有非空判断,但是线程这个东西是由时间片控制的,如果一个线程刚刚非空判断通过了,然后切换到下个线程,也执行并通过非空判断,并切换到上一个线程,其实两个线程都会执行new操作,就不单例了!(虽然发生概率不高)但是我们为了更加的准确,我们来看看线程安全的版本怎么写

public class Singleton {
private static Singleton instance;

private Singleton(){}

public static synchronized Singleton getInstance() {
    if(null == instance){
        instance = new Singleton();
    }
    return instance;
} }

结论: 只是在 getInstance() 前添加了 synchronized
关键字,保证同一时刻只能有一个线程执行获取到类锁,并执行创建实例代码,保证了只会创建一次。同时也有了懒加载的特性。

但是但是, 由于是单例模式,如果将锁直接锁在 static
的方法上(相当于类锁,其他static方法也不能执行),那么效率是非常低的,所以我们还有一定的改进。

双重检查加锁

public class Singleton {
private static volatile Singleton instance;

private Singleton() {
}

public static Singleton getInstance() {
    if (null == instance) {
        synchronized (Singleton.class) {
            if (null == instance) {
                instance = new Singleton();
            }
        }
    }
    return instance;
} }

懒加载:
确保线程安全 只有第一次创建类的时候可能发生阻塞,后面由于非空判断都不会阻塞
volatile是什么鬼?如果你关注线程安全的话就会了解,volatile是用来保证多个线程并发时,访问的都是内存中的同一个volatile对象。

枚举单例

public enum Singleton {
INSTANCE; }

What the fuck? 就3行,好吧,我也是刚刚学的,解释一下原理,枚举类型也是在第一次被使用的时候初始化,并且默认构造函数是private修饰,而且线程安全。

序列化问题

传统单例写法,如果实现了序列化接口,他们就不能再保持单例,因为readObject() 方法每次会返回新的对象,所以你需要重写这个方法:

private Object readResolve(){
return INSTANCE; }


好啦,单例模式就介绍到这里,如果还没看懂就自个动手编码哈~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值