双重检验锁方式实现单例模式

单例模式(Singleton Pattern)是指在内存中只会创建且仅创建一次对象的设计模式。在程序中多次使用同一个对象且作用相同时,为了防止频繁地创建对象使得内存飙升,单例模式可以让程序仅在内存中创建一个对象,让所有需要调用的地方都共享这一单例对象。

单例模式有两种类型:

        1,饿汉式:就是说我很饿看到啥都吃,也就是在类加载的时候就创建给对象。

        2,懒汉式:不是很饿,当真正用到该对象的时候才进行创建。

单例模式注意

        1,单例类只能有一个实例

        2,单例类必须自己创建自己的唯一实例(对象不能new出来)

        3,单例类必须给所有其他对象提供自己创建好的实例

1,对应Java代码实现-饿汉式

//饿汉单例
public class HungrySingle {//构造器私有private HungrySingle(){}//创建自己的唯一实例private static final HungrySingle HUNGRY_SINGLE=new HungrySingle();//对外提供自己的这唯一实例private static HungrySingle getInstance(){return HUNGRY_SINGLE;}
}

2,对应Java代码实现-懒汉式

//懒汉单例
public class LazySingle {//构造器私有private LazySingle(){}private static LazySingle LAZY_SINGLE;private static LazySingle getInstance(){//当前实例没有被创建的时候才行创建if(LAZY_SINGLE==null){LAZY_SINGLE=new LazySingle();}return LAZY_SINGLE;}
}

3,双重检验锁方式实现单例模式   

上述的懒汉单例实现是不完美的,因为我们创建实例的时候需要先判断是否为空,单如果实在多线程环境下,同时判断这个实例对象为空于是就创建了不同的对象,测试如下:

package com.qmlx.springbootinit.Pattern;
//懒汉单例
public class LazySingle {//构造器私有private LazySingle(){System.out.println(Thread.currentThread().getName()+"线程创建了对象");}private static LazySingle LAZY_SINGLE;private static LazySingle getInstance(){//当前实例没有被创建的时候才行创建if(LAZY_SINGLE==null){LAZY_SINGLE=new LazySingle();}return LAZY_SINGLE;}public static void main(String[] args) {for (int i = 0; i < 10; i++) {new Thread(()->{LazySingle instance = LazySingle.getInstance();System.out.println(instance);}).start();}}
}

代码执行结果如下:

 根据输出以及当前创建的对象,我们可以看到他创建了不同的对象,所以,为了解决这个方法,我们在创建对象的时候使用 synchronized关键字包裹  这样我们就能保证创建对象的操作式互斥的,从而保证对象的单例,这就是常说的双重检验锁方式实现单例模式

代码如下:

//懒汉单例
public class LazySingle {//构造器私有private LazySingle(){System.out.println(Thread.currentThread().getName()+"线程创建了对象");}private static LazySingle LAZY_SINGLE;private static LazySingle getInstance(){//当前实例没有被创建的时候才行创建if(LAZY_SINGLE==null){synchronized (LazySingle.class){if(LAZY_SINGLE==null){LAZY_SINGLE=new LazySingle();}}}return LAZY_SINGLE;}public static void main(String[] args) {for (int i = 0; i < 10; i++) {new Thread(()->{LazySingle instance = LazySingle.getInstance();System.out.println(instance);}).start();}}}

但是他依旧存在问题,继续往下看。

LAZY_SINGLE=new LazySingle();

这段代码并不是原子性的,因为这段代码其实是分为三部分来执行的:

1,为LAZY_SINGLE分配内存空间

2,初始化LAZY_SINGLE,也就是执行构造方法去初始化这个对象

3,将LAZY_SINGLE指向分配的内存地址

正常步骤是1->2->3,但是JVM具有指令重排序的特性,在单线程下是不会存在问题的,但是在多线程下,会导致一个线程拿到还没有进行初始化的实例,例如线程1执行了1->3,然后线程二获取这个实例,发现不为空,拿到但是结果是没有初始化的。

4,如何防止指令重排序呢?

我们可以使用volatile关键字,他有两个关键作用:

1,保证线程间共享变量的可见性(防止了JIT对共享变量的优化),例如

你写的代码------------------>JIT优化之后的代码

 

所以,我们对变量添加volatile关键字就是告诉JIT编译器,我这个变量你不要优化。

2,防止指令重排序(JVM对程序执行中的优化)

所以我们对当前变量添加volatile关键字,当对这个变量进行读写操作的时候会通过擦汗如特定的内存屏障的方式来禁止指令重排序

具体如下(我的笔记,不知道可不可以帮助理解)

最终代码如下:

//懒汉单例
public class LazySingle {//构造器私有private LazySingle(){System.out.println(Thread.currentThread().getName()+"线程创建了对象");}private static volatile LazySingle LAZY_SINGLE;private static LazySingle getInstance(){//当前实例没有被创建的时候才行创建if(LAZY_SINGLE==null){synchronized (LazySingle.class){if(LAZY_SINGLE==null){LAZY_SINGLE=new LazySingle();}}}return LAZY_SINGLE;}}

 其实这种实现方式也不是完美的,因为Java中那可是存在反射的,他就可以破坏对象的单例!

具体如何???

等我深刻理解之后,在谈!!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/670667.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【C++语言】类和对象--默认成员函数 (中)

文章目录 前言类的六个默认成员函数&#xff1a;1. 构造函数概念特性做了什么&#xff1f;易错注意&#xff1a;显式定义和默认构造函数 2. 析构函数概念特征做了什么?注意事项&#xff1a; 3.拷贝构造函数概念特征做了什么&#xff1f;注意事项&#xff1a; 4.赋值运算符重载…

微搭低代码入门03页面管理

目录 1 创建页面2 页面布局3 页面跳转总结 上一篇我们介绍了应用的基本操作&#xff0c;掌握了应用的概念后接着我们需要掌握页面的常见操作。 1 创建页面 打开应用的编辑器&#xff0c;在顶部导航条点击创建页面图标 在创建页面的时候可以从空白新建&#xff0c;也可以使用模…

rust调用SQLite实例

rusqlite库介绍 Rusqlite是一个用Rust编写的SQLite库&#xff0c;它提供了对SQLite数据库的操作功能。Rusqlite的设计目标是提供一个简洁易用的API&#xff0c;以便于Rust程序员能够方便地访问和操作SQLite数据库。 Rusqlite的主要特点包括&#xff1a; 遵循Rust的类型系统和…

电机控制器电路板布局布线参考指导(七)电流检测模块布局布线

电机控制器电路板布局布线参考指导&#xff08;七&#xff09;电流检测模块布局布线 1.高侧电流检测2.低侧电流监测3.两相和三相电流检测4.关键元器件选型要求5.布局6.布线7.工具设置8.输入和输出滤波9.注意事项 很多电机驱动器产品系列包括内置了电流感测功能的器件&#xff0…

vue3中标签的ref属性

组合API-ref属性 在vue2.x中&#xff0c;可以通过给元素添加refxxx属性&#xff0c;然后在代码中通过this.$refs.xxx获取到对应的元素 然而在vue3中时没有$refs这个东西的&#xff0c;因此vue3中通过ref属性获取元素就不能按照vue2的方式来获取。 目标&#xff1a;掌握使用re…

LLM⊗KG范式下的知识图谱问答实现框架思想阅读

分享一张有趣的图&#xff0c;意思是在分类场景下&#xff0c;使用大模型和fasttext的效果&#xff0c;评论也很逗。 这其实背后的逻辑是&#xff0c;在类别众多的分类场景下&#xff0c;尤其是在标注数据量不缺的情况下&#xff0c;大模型的收益是否能够比有监督模型的收益更多…

Pytorch实现图片异常检测

图片异常检测 异常检测指的是在正常的图片中找到异常的数据&#xff0c;由于无法通过规则进行识别判断&#xff0c;这样的应用场景通常都是需要人工进行识别&#xff0c;比如残次品的识别&#xff0c;图片异常识别模型的目标是可以代替或者辅助人工进行识别异常图片。 AnoGAN…

4+1视图,注意区分类图与对象图

注意区分类图和对象图。对象图标记的是对象名&#xff0c;命名形式 对象名:类名&#xff0c;或者:类名。这里没有出现冒号&#xff0c;表示的是类图。 对象图(object diagram)。 对象图描述一组对象及它们之间的关系。对象图描述了在类图中所建立的事物实例的静态快照。和类图一…

表空间的概述

目录 表空间的属性 表空间的类型 永久性表空间(PermanentTablespace) 临时表空间(Temp Tablespace ) 撤销表空间(Undo Tablespace) 大文件表空间(BigfileTablespace) 表空间的状态 联机状态(Online) 读写状态(Read Write) 只读状态(Read) 脱机状态(Offline) Oracle从…

四川景源畅信:抖音个人开通橱窗操作流程介绍详情

随着短视频平台的快速发展&#xff0c;抖音已经成为越来越多人展示自我、分享生活的舞台。而其中&#xff0c;个人橱窗功能则为内容创作者提供了一个展示和销售商品的窗口。如果你是一位想要在抖音上开通个人橱窗的创作者或商家&#xff0c;了解详细的操作流程是迈向成功的第一…

iconfont_vue小程序中使用

1.前三步就是简单下载&#xff0c;详细可看这篇 vue管理系统导航中添加新的iconfont的图标-CSDN博客 2.引用有点区别&#xff1a;在App中引用 3.uni-icons写法 <uni-icons custom-prefix"iconfont" type"icon-zhengjian" size"23"></un…

博客网站SpringBoot+Vue项目练习

博客网站SpringBootVue简单案例 前言 学了vue后一直没用找到应用的机会&#xff0c;在Github上找到了一个看起来比较友好的项目&#xff08;其实具体代码我还没看过&#xff09;。而且这个项目作者的readme文档写的也算是比较好的了。 项目链接&#xff1a;https://github.c…