一、前言
1.单例模式
保证一个类只有一个实例。
常见的应用场景:线程池,方便对池中的线程进行管理
2.单例优缺点:
优点:
①在单例模式中,活动的单例只有一个实例,对单例类的所有实例化得到的都是相同的一个实例。这样就 防止其它对象对自己的实例化,确保所有的对象都访问一个实例
②单例模式具有一定的伸缩性,类自己来控制实例化进程,类就在改变实例化进程上有相应的伸缩性。
③提供了对唯一实例的受控访问。
④由于在系统内存中只存在一个对象,因此可以 节约系统资源,当 需要频繁创建和销毁的对象时单例模式无疑可以提高系统的性能。
⑤允许可变数目的实例。
⑥避免对共享资源的多重占用。
缺点:
①不适用于变化的对象,如果同一类型的对象总是要在不同的用例场景发生变化,单例就会引起数据的错误,不能保存彼此的状态。
②由于单利模式中没有抽象层,因此单例类的扩展有很大的困难。
③单例类的职责过重,在一定程度上违背了“单一职责原则”。
④滥用单例将带来一些负面问题,如为了节省资源将数据库连接池对象设计为的单例类,可能会导致共享连接池对象的程序过多而出现连接池溢出;如果实例化的对象长时间不被利用,系统会认为是垃圾而被回收,这将导致对象状态的丢
二、饿汉式单例 --立即加载
/**
* 饿汉式单例
* 初始化时就已经实例化对象了
* 缺点:一初始化就会实例静态变量,JVM方法区就会为变量分配内存,GC并不会回收,直到类被卸载时静态变量被摧毁才会回收
* 线程天生安全
*/
public class HungrySingleton {
//保证只有一个实例
private static final HungrySingleton hungrySingleton = new HungrySingleton();
//构造函数私有化
private HungrySingleton() {
System.out.println("饿汉式构造函数初始化");
}
//获取对象
public static HungrySingleton getInstance(){
return hungrySingleton;
}
}
三、懒汉式单例–延迟加载
/**
* 懒汉式单例
* 调用者需要时才实例化对象
* 懒汉式单例本身线程不安全
*/
public class LazySingleton {
private static LazySingleton lazySingleton;
private LazySingleton() {
System.out.println("懒汉式构造函数初始化");
}
//synchronized 目的为了解决线程不安全问题,但是因为它是悲观锁,线程会阻塞,浪费资源
public synchronized static LazySingleton getInstance() {
if (lazySingleton == null) {
lazySingleton = new LazySingleton();
}
return lazySingleton;
}
}
四、静态内部类
优势:兼顾了懒汉模式的内存优化(使用时才初始化)以及饿汉模式的安全性(不会被反射入侵)。
劣势:需要两个类去做到这一点,虽然不会创建静态内部类的对象,但是其 Class 对象还是会被创建,而且是属于永久代的对象(在Java 8中,永久代被彻底移除,取而代之的是另一块与堆不相连的本地内存——元空间)。
/**
* 静态内部类
*/
public class StaticSingleton {
private StaticSingleton(){
System.out.println("静态内部类初始化");
}
public static class SingletonClassInstance{
private static final StaticSingleton staticSingleton = new StaticSingleton();
}
public static StaticSingleton getInstance(){
return SingletonClassInstance.staticSingleton;
}
}
五、枚举–线程安全
优点:实现简单、枚举本身就是单例,由JVM从根本上提供保障!避免通过反射和反序列化的漏洞 缺点没有延迟加载
/**
* 枚举
*/
public class Demo4 {
private static enum EnumSingleton {
INSTANCE;
private Demo4 demo4;
private EnumSingleton() {
demo4 = new Demo4();
System.out.println("枚举单例初始化");
}
public Demo4 getInstance() {
return demo4;
}
}
public static Demo4 getInstance() {
return EnumSingleton.INSTANCE.getInstance();
}
}
六、双重检测锁
public class SingletonDemo04 {
private SingletonDemo04 singletonDemo04;
private SingletonDemo04() {
}
public SingletonDemo04 getInstance() {
if (singletonDemo04 == null) {
synchronized (this) {
if (singletonDemo04 == null) {
singletonDemo04 = new SingletonDemo04();
}
}
}
return singletonDemo04;
}
}