当前位置:网站首页>简单了解单例模式
简单了解单例模式
2022-07-29 12:55:00 【何以解忧,唯有..】
一、前言
单例模式是指在内存中有且只会创建一次对象的设计模式,在程序中多次使用同一个对象且作用相同的时候,为了防止频繁的创建对象,单例模式可以让程序在内存中创建一个对象,让所有的调用者都共享这一单例对象。单例模式的类型有两种:懒汉式和饿汉式。
二 单例模式类型
饿汉式:在类加载的时候已经创建好该单例对象。
懒汉式:在需要使用对象的时候才会去创建对象
2.1 饿汉式:
//饿汉式
public class Hungry {
/** * 构造器私有 拒绝别人创建这个对象 */
private Hungry() {
}
private final static Hungry HUNGRY = new Hungry();
public static Hungry getInstance(){
return HUNGRY;
}
大家都知道饿汉式单例是程序启动的时候就已经创建好了对象,那么这样的会会有什么问题呢?有可能浪费空间,为什么呢?因为如果在该类中声明了许多内存空间,但却没有使用的话,就很浪费内存空间,因为饿汉式它是在程序启动的时候就已经创建好了。
2.2 懒汉式:
//懒汉式单例
public class LazySingle {
private LazySingle(){
}
private static LazySingle lazySingle;
public static LazySingle getInstance(){
if (lazySingle == null ) {
lazySingle = new LazySingle();
}
return lazySingle;
}
}
2.3 双重检查锁:
但是这样会不会有问题呢?这样创建的懒汉式单例模式在单线程环境下肯定是没问题的,但是在多线程环境下,就会有问题了。就会不止创建一个对象了,那么如何改进呢?如下:
//懒汉式单例
public class LazySingle {
private LazySingle(){
System.out.println(Thread.currentThread().getName()+"ok");
}
private static LazySingle lazySingle;
//双重检查加锁
public static LazySingle getInstance(){
if (lazySingle == null ){
synchronized (LazySingle.class){
if (lazySingle == null ) {
lazySingle = new LazySingle();
}
}
}
return lazySingle;
}
这就是双重检查加锁的机制了(DCL懒汉式),这样就可以保证在多线程环境下有且仅会创建一个对象。
2.4 volatile防止指令重排:
那么这样的双重检查锁是完整的吗,会不会出现一些其他的问题呢?其实也是会的,因为当我们在 new LazySingle()的时候,其实是有可能发生指令重排的。
1 分配内存空间
2 执行构造方法,初始化对象
3 把这个对象指向这个空间
正常情况下,执行的这个顺序是1,2,3,如果在发生了指令重排,并且在多线程的环境下,也会出现问题。比如:A线程指令重排1,3,2,那么在重排过程中线程B进来,发现lazySingle已经分配内存空间了,不等于null了,那么就直接返回了,对于这种情况应该怎样处理呢?可以使用volatile关键字来解决,如下:
//懒汉式单例
public class LazySingle {
private LazySingle(){
System.out.println(Thread.currentThread().getName()+"ok");
}
private volatile static LazySingle lazySingle;
//双重检查加锁
public static LazySingle getInstance(){
if (lazySingle == null ){
synchronized (LazySingle.class){
if (lazySingle == null ) {
lazySingle = new LazySingle();
}
}
}
return lazySingle;
}
}
2.5 静态内部类
//静态内部类
public class Holder {
private Holder(){
}
public static Holder getInstance(){
return InnerClass.HOLDER;
}
public static class InnerClass{
private static final Holder HOLDER = new Holder();
}
}
边栏推荐
猜你喜欢

Sentinel 2A data preprocessing and calculation of six common vegetation indices in snap software

Leetcode65. 有效数字

Leetcode66. 加一

【MySQL】ERROR 2002 (HY000): Can‘t connect to local MySQL server through socket ‘/tmp/mysql.sock‘

基于对象的实时空间音频渲染丨Dev for Dev 专栏
![[Mysql] LENGTH函数](/img/a1/112cac6b42f8c7abec7e4a6629dffd.png)
[Mysql] LENGTH函数

传奇人形怪爆率怎么设置?人形怪增加教程

【微信小程序】WXSS和全局、页面配置

Container is changed | deploy MySQL cluster in the Rancher

pycharm专业版使用
随机推荐
MySQL database installation (detailed)
C# 1秒跑一个数字的展示,主要练习 事件相关内容
DVWA full level customs clearance tutorial
传奇人形怪爆率怎么设置?人形怪增加教程
MIT指出公开预训练模型不能乱用
关闭线程池 shutdown 和 shutdownNow 的区别
The torch using summary
IJCAI 2022杰出论文公布,大陆作者中稿298篇拿下两项第一
DBeaver 安装及配置离线驱动
mysql数据库安装(详细)
Research on the thinking and application methods of the frontier of ESI research
[Numpy] 创建数组
Go-Excelize API源码阅读(七)—— CopySheet(from, to int)
线程池拒绝策略详解
[网鼎杯 2020 半决赛]AliceWebsite
hash table 实现代码
电子游戏的核心原理
html+css+php+mysql实现注册+登录+修改密码(附完整代码)
[WeChat applet] WXSS and global, page configuration
Leetcode65. 有效数字