单例模式:一种创建型设计模式, 让你能够保证一个类只有一个实例, 并提供一个访问该实例的全局节点。
方法为私有化构造函数,在类中定义静态实例(先new为饿汉 后new为懒汉)
在方法定义静态方法,返回唯一实例
下面介绍三种单例模式java代码写法
1。懒汉式(需要用时再申请)缺点:有线程不安全风险
(2021/1/18更新:为什么不安全呢?
竞态条件的类型“先检查后执行”的一种情况——延迟初始化
假设有线程A B同时执行这个方法,A看到是null的,取决于时序、线程调度方式,如果B同样需要看到是null的(未初始化完成),则会出现覆盖)
class lhan { private int address = 1999; private static lhan instance; //私有化构造函数 外部只能用实例调用 无法新声明新实例 private lhan() { } void put(int k) { address = k; return; } int get() { return address; } //返回唯一实例 public static lhan getInstance() { if (instance == null) { instance = new lhan(); } return instance; } }
2.饿汉式(不管是否调用 先申请) 优点:线程安全。 缺点:如果不调用的话浪费内存
class ehan{ private int age=20; private ehan(){};//私有化构造函数 private static ehan instance=new ehan(); void put(int k) { age = k; return; } public int get() { return age; } public static ehan getInstance() { return instance; } }
3.双检锁式(综合了饿汉 懒汉的优点 并改正了其缺点)
这样既保证了线程安全,又比直接上锁提高了执行效率,还节省了内存空间。
class DoubleCheack{ private static DoubleCheack instance; private int age=1; private DoubleCheack(){}; void put(int k) { age = k; return; } public int get() { return age; } public static DoubleCheack getInstance() { if(instance==null) {//先判断是否为null 后上锁进行初始化 synchronized (DoubleCheack.class) { if (instance == null)//将对象上锁之后再次判断 是否有别的线程初始化了 instance = new DoubleCheack(); } } return instance; } }
主函数测试用例(双检锁)
无论对于几个实例内数据如何变动 都指向一个唯一实例(instance)
参考博文:
https://blog.csdn.net/absolute_chen/article/details/93380566