单例模式:单例模式的意思就是只有一个实例。单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。这个类称为单例类。
单例模式主要有三种:
分别是懒汉式单例,饿汉式单例,登记式单例(懒汉模式变种,使用静态内部类创建)。
1.懒汉式单例
/**
* 这个是懒汉模式,线程安全的
*/
public class Singleton {
private static Singleton singleton;
private Singleton() {} //此类不能被实例化
// 加上 synchronized 保证创建线程线程安全
public static synchronized Singleton getInstance() {
if (singleton == null) {
singleton = new Singleton();
}
return singleton;
}
}
优点:第一次调用才初始化,避免内存浪费。
缺点:必须加锁synchronized 才能保证单例,(如果两个线程同时调用getInstance方法,会chuxia)但加锁会影响效率。
2.饿汉式单例
/**
* 这个是饿汉模式,类一加载就要初始化
*/
public class SingletonDemo3 {
// 在成员变量声明的时候就要初始化
private static SingletonDemo3 instance = new SingletonDemo3();
private SingletonDemo3() {
}
public static SingletonDemo3 getInstance() {
// 若当前实例为空,重新指向一个新的实例
if (instance == null) {
instance = new SingletonDemo3();
}
return instance;
}
}
优点:没有加锁,执行效率会提高。
缺点:类加载时就初始化,浪费内存。
3.登记式模式(holder)
内部类只有在外部类被调用才加载,产生Singleton实例;又不用加锁。此模式有上述两个模式的优点,屏蔽了它们的缺点,是最好的单例模式。
/**
* 这个是懒汉模式变种,使用静态内部类创建
*/
public class SingletonDemo4 {
private static class SingletonHolder{
private static final SingletonDemo4 instance = new SingletonDemo4();
}
private SingletonDemo4() {
}
public static SingletonDemo4 getInstance() {
// 调用内部类的属性创建新的实例
return SingletonHolder.instance;
}
}
静态内部类这种方式同样利用了classloder的机制来保证初始化instance时只有一个线程,它跟前几种方式不同的是:Singleton类被装载了,instance不一定被初始化。因为SingletonHolder类没有被主动使用,只有显示通过调用getInstance方法时,才会显示装载SingletonHolder类,从而实例化instance。想象一下,如果实例化instance很消耗资源,我想让他延迟加载,另外一方面,我不希望在Singleton类加载时就实例化,因为我不能确保Singleton类还可能在其他的地方被主动使用从而被加载,那么这个时候实例化instance显然是不合适的。这个时候,这种方式相比饿汉方法就显得更合理。
若单例对象占用资源少,不需要延迟加载,那么使用枚举好于饿汉式,因为枚举十分安全,耗时差不多。
若单例对象占用资源多,需要延迟加载,那么使用内部类好于懒汉式,耗时差距明显。
对文章有何见解,或者有何技术问题,都可以在评论区一起留言讨论,一定会回复的。
也欢迎大家来我的B站找我玩,各类Android架构师进阶技术难点的视频讲解,任君白嫖。
B站直通车:https://space.bilibili.com/484587989
网友评论