特别感谢作者带我进入单例模式的世界:
圣诞节,让我们聊聊单例模式
https://www.jianshu.com/p/31345e4f21e7
暂时还没有深入了解 枚举单例模式和Spring的@Scope("singleton")实现方式,暂且给自己一个课后作业吧。
枚举单例模式
代码内容:
public enum EasySingleton{
INSTANCE;
}
为什么java中用枚举实现单例模式会更好
https://www.jianshu.com/p/7b3de9e0c983
饿汉模式——空间换取时间
代码内容:
public class Singleton {
private Singleton(){} //默认构造器
private static Singleton instance = new Singleton();//直接加载
public Singleton getIntance(){
return instance;
}
懒汉模式,延时加载——时间换取空间
代码内容:
public class Singleton {
private Singleton() { } // 默认构造器
private static Singleton instance = null;// 延时加载
//每次运行都要创建实例因而需要加锁保护
public static synchronized Singleton getIntance() {
if (instance == null) {
instance = new Singleton();// 判断之后加载
}
return instance;
}
为什么需要双重检测?
所谓双重检查加锁机制,指的是:
并不是每次进入getInstance方法都需要同步,而是先不同步,进入方法过后,先检查实例是否存在,如果不存在才进入下面的同步块,这是第一重检查。进入同步块过后,再次检查实例是否存在,如果不存在,就在同步的情况下创建一个实例,这是第二重检查。这样一来,就只需要同步一次了,从而减少了多次在同步情况下进行判断所浪费的时间。
双重检查加锁机制的实现会使用一个关键字
volatile,它的意思是:被volatile修饰的变量的值,将不会被本地线程缓存,所有对该变量的读写都是直接操作共享内存,从而确保多个线程能正确的处理该变量。
注意:在Java1.4及以前版本中,很多JVM对于volatile关键字的实现有问题,会导致双重检查加锁的失败,因此双重检查加锁的机制只能用在
Java5及以上的版本。
单例模式和双重检测的小结
https://yq.aliyun.com/articles/48661
克隆、序列化和反射可以破坏单例模式
参考文档:
https://blog.csdn.net/qq_40396127/article/details/78794837
如何粗鲁的破坏一个单例模式
克隆
克隆方式破坏是一种良性的单例模式破坏方法。
克隆破坏单例模式需要继承Colneable接口并且重写克隆方法,当你的代码这么写的时候意味着你为了以后破坏这个单例模式做出了准备。
反射
原因
:反射通过setAccessible(true)的方法是java跳过检测语法
解决方法:
在私有构造方法中增加内部静态类同步锁的静态计数器,当计数器大于1时,抛出错误。
序列化
原因:序列化底层采用反射时会检查,实现了序列化接口的类是否包含readResolve,如果包含则返回true,然后会调用readResolve方法。
解决方法:实现私有方法readResolve()方法,返回Object类的实例。
private Object readResolve() {
return doubleLockSingleton;
}
具体内容了解链接地址:
http://www.hollischuang.com/archives/1144
单例与序列化的那些事儿