目录
单例模式(Singleton Pattern)是指确保一个类在一个容器下只有一个实例存在,并提供一个全局访问点。
(单例模式最大的特点就是构造方法私有化)
1.饿汉式单例
UML类结构图:
定义:
饿汉式单例是在类加载的时候就立即初始化,并且创建单例对象。绝对线程安全,在线程还没出现以前就实例化了,不可能存在访问安全问题。
(Spring IOC容器中ApplicationContext本身就是典型的饿汉式单例。)
优点:
没有加任何的锁,执行效率比较高,在用户体验上来说,比懒汉式更好。
缺点:
类加载的时候就初始化,不管用与不用都占用着空间,浪费内存。
代码实现:
HungrySingletonTest类
写法一:
public class HungrySingletonTest {
//写法一
private static final HungrySingletonTest hungrySingletonTest = new HungrySingletonTest();
private HungrySingletonTest() {}
public static HungrySingletonTest getInstance() {
return hungrySingletonTest;
}
}
写法二:
public class HungrySingletonTest {
// 写法二
private static HungrySingletonTest hungrySingletonTest;
static {
hungrySingletonTest = new HungrySingletonTest();
}
private HungrySingletonTest() {}
public static HungrySingletonTest getInstance() {
return hungrySingletonTest;
}
}
注意:
饿汉式虽然是线程安全的,但是如果我们使用FileInputStream / FileOutputStream配合ObjectInputStream / ObjectOutputStream来把实例序列化之后,再反序列化回来,还是会变成两个对象。
解决方法:
需要在单例类中实现Serializable序列化接口,并且实现readResolve()方法,这是序列化和反序列化的一个协议,为了序列化后的对象能够重复利用,可以实现readResolve()方法,而这个方法是由JVM自动调用的。
private Object readResolve() {
return INSTANCE; // 返回饿汉式中的静态实例
}
2.懒汉式单例
类结构图:
定义:
懒汉式单例的特点是:被外部类调用的时候单例类才会实例化。
优点:
当单例类被外部类调用的时候单例类才会实例化,相比饿汉式不会浪费内存。
缺点:
容易出现线程安全,如果用双重锁保证线程安全,也会因此降低性能。
代码实现:
LazySingletonTest类
public class LazySingletonTest {
private static LazySingletonTest lazySingletonTest;
private LazySingletonTest() {}
public static LazySingletonTest getInstance() {
// 双重锁增加线程安全
// 第一个if()减少synchronized使用频率,提高性能
if (lazySingletonTest == null) {
synchronized (LazySingletonTest.class) {
// 第二个if()去除已经在并发线程中实例化的变量
if (lazySingletonTest == null) {
lazySingletonTest = new LazySingletonTest();
}
}
}
return lazySingletonTest;
}
}
3.单例模式完美解决方案
// 这种形式兼顾饿汉式的内存浪费,也兼顾synchronized性能问题
// 完美地屏蔽了这两个缺点
public class LazySingletonTest {
// 默认使用LazySingleTest的时候,会先初始化内部类
// 如果没使用的话,内部类是不加载的
private LazySingletonTest() {}
// 每一个关键字都不是多余的
// static是为了使单例的空间共享
// 保证这个方法不会被重写,重载
public static final LazySingletonTest getInstance() {
// 在返回结果以前,一定会先加载内部类
return LazyHolder.LAZY;
}
// 默认不加载
private static class LazyHolder {
private static final LazySingletonTest LAZY = new LazySingletonTest();
}
}