单例模式(DCL、holder等)
单利模式
单利模式简单的来说由两部分组成:
- 只实例化一次
- 提供返回这个实例的方法
单利模式的好坏在于线程安全、性能(效率)、懒加载这三个属性的好坏
那怎么实现单利模式呢?也就是怎么才能保证一直只有一个实例呢?
很快我们就能想到static关键字
饿汉模式
public class HungerySingletonDemo {private static HungerySingletonDemo instance=new HungerySingletonDemo();private HungerySingletonDemo() {}public static HungerySingletonDemo getInstance() {return instance;}
}
线程安全、性能好,但是不能实现懒加载,当HungerySingletonDemo占用变大时会非常占用内存(一开始不使用这个对象却要占用大量内存)
懒汉模式
先要实现懒加载,就在第一次调用的时候实例它好了
public class HoonSingleton {private static HoonSingleton instance=null;private HoonSingleton() {}public static HoonSingleton getInstance() {if(instance==null) {instance = new HoonSingleton();}return instance;}
}
实现了懒加载,但是线程不安全,因为如果当多个线程同时访问到if(instance==null)
这行代码,都会执行到 if 内部,这样就会创建多个实例。线程都不安全就没有性能好坏这个说法了。
那有没有这么方法来改进呢?也就是怎么控制线程的并发访问呢?
很明显我们会想到synchronized关键字。
public static synchronized HoonSingleton getInstance()
这样的话线程就可同步访问getInstance这个方法,就不会创建这个实例了
但问题又随着而来了,synchronized效率太低了,性能不好。那怎么才能提高性能呢?这时,我们可能会想到让同步代码执行次数少点不就好了吗,那怎么才能使同步代码执行次数变少呢?请看下例DCL。
DCL(Double Check Lock)
public static HoonSingleton getInstance() {if(instance==null) {synchronized(HoonSingleton.class) {instance = new HoonSingleton();}}return instance;
}
如上,是不是减少了同步代码的执行次数(instance==null就不会执行同步代码)
但是这样的话有出现了线程安全的问题,因为如果有多个线程都进入到instance==null
里面的 if 语句块,就会在synchronized代码块进行并发操作,无论如何最后都会并发完,结果也会创建多个实例。那如何改进呢?这就是DCL(执行两次判断语句)。
public class DCLSingleton {private static DCLSingleton instance=null;private DCLSingleton() {}public static DCLSingleton getInstance() {if(instance==null) {synchronized(DCLSingleton.class) {if(instance==null) {instance = new DCLSingleton();}}}return instance;}
}
如上,判断了两次instance==null
,这就防止了创建多个实例(synchronized内部再判断一次,如果不为空就不创建实例)。但这个有可能会存在问题,如下:
存在问题:
假设线程一执行到instance = new DCLSingleton();
这句,这里看起来是一句话,但实际上其被编译后在JVM执行的对应会变代码就发现,这句话被编译成8条汇编指令,大致做了三件事情:
1)给instance实例分配内存;
2)初始化instance的构造器;
3)将instance对象指向分配的内存空间(注意到这步时instance就非null了)
如果指令按照顺序执行倒也无妨,但JVM为了优化指令,提高程序运行效率,允许指令重排序。如此,在程序真正运行时以上指令执行顺序可能是这样的:
a)给instance实例分配内存;
b)将instance对象指向分配的内存空间;
c)初始化instance的构造器;
这时候,当线程一执行b)完毕,在执行c)之前,被切换到线程二上,这时候instance判断为非空,此时线程二直接来到return instance语句,拿走instance然后使用,接着就顺理成章地报错(对象尚未初始化)。
具体来说就是synchronized虽然保证了线程的原子性(即synchronized块中的语句要么全部执行,要么一条也不执行),但单条语句编译后形成的指令并不是一个原子操作(即可能该条语句的部分指令未得到执行,就被切换到另一个线程了)。
根据以上分析可知,解决这个问题的方法是:禁止指令重排序优化(相对的),即使用volatile变量。
private static volatile DCLSingleton instance=null;//在该属性上加volatile
Holder模式(使用广泛)
声明类时不声明实例变量,而放到一个内部静态类中去实例化该类
public class HolderSingleton {private static class Holder{private static HolderSingleton instance=new HolderSingleton();}public static HolderSingleton getInstance() {return HolderSingleton.Holder.instance;}
}
加载HolderSingleton时,也会加载内部类Holder,但它不会初始化,当首次调用getInstance时才初始化化(就是实现了懒加载)。
枚举模式(使用广泛)
Holder模式的内部类替换成enum类型的,因为枚举类型的成员时(INSTANCE)也是public static final的,且是在static{}中初始化的(就是实现了懒加载)。
public class EnumSingleton {private EnumSingleton() {}private enum EnumHolder{INSTANCE;//public static final EnumHolder实例,在static块初始化private EnumSingleton instance=null;//EnumHolder实例的私有变量EnumHolder(){instance = new EnumSingleton();}}public static EnumSingleton getInstance() {return EnumHolder.INSTANCE.instance;}}
单例模式(DCL、holder等)相关推荐
- java单例模式(Holder模式美滋滋)
饱汉模式(懒汉模式) // 饱汉// 非线程安全public class Singleton1 {private static Singleton1 singleton = null;private ...
- java 单例 dcl_java 中单例模式DCL的缺陷及单例的正确写法
1 前言 单例模式是我们经常使用的一种模式,一般来说很多资料都建议我们写成如下的模式: /** * Created by qiyei2015 on 2017/5/13. */ public class ...
- 面试官:你写的单例模式有空指针异常,请你用Volatile改一下。我愣了五分钟...
1 单例模式 大家对单例模式并不会陌生,当创建一个对象需要消耗比较多资源时,例如创建数据库连接和消息服务端等等,这时我们选择只创建一份这种类型的对象并在进程内共享. 但是单例模式想要写好并不容易,我们 ...
- Android设计模式之——单例模式
一.介绍 单例模式是应用最广的模式之一,也可能是很多初级工程师唯一会使用的设计模式.在应用这个模式时,单例对象的类必须保证只有一个实例存在.许多时候整个系统只需要拥有一个全局对象,这样有利于我们协调系 ...
- 高并发下线程安全的单例模式(最全最经典,值得收藏)
作者:mlinge-奋斗吧 blog.csdn.net/cselmu9/article/details/51366946 在所有的设计模式中,单例模式是我们在项目开发中最为常见的设计模式之一,而单例模 ...
- Dubbo流程及源码分析(一)
扑街前言:之前的文章说明了zookeeper的使用及源码,那么本次我们继续了解和zookeeper的黄金搭档dubbo的相关内容,当然dubbo也是典型的rpc框架,所以我们从客户端和服务端逐个分析, ...
- 多线程进阶(并发编程JUC)
多线程进阶(并发编程JUC) 提示: 本材料只做个人学习参考,不作为系统的学习流程,请注意识别!!! 并发编程JUC 1. 基础知识 什么是JUC(Java并发包)?并发编程的本质(充分利用CPU的资 ...
- 线程间怎么交换数据_2 万字长文详解 10 大多线程面试题|原力计划
作者 | ZZZhonngger 责编 | 伍杏玲 出品 | CSDN博客 Volatile相关 1.请谈谈你对 volatile 的理解 答:volatile 是 Java 虚拟机提供的轻量级的同步 ...
- 互联网大厂高频重点面试题
1.volatile是Java虚拟机提供的轻量级的同步机制 volatile提供的轻量级的同步机制 1.1保证可见性 1.2不保证原子性 1.3禁止指令重排 1.4JMM(Java Memory Mo ...
最新文章
- 一致性哈希算法介绍,及java实现
- AI公开课:19.04.04李航—字节跳动AILab总监《深度学习与自然语言处理:评析与展望》课堂笔记以及个人感悟
- sql两个数字之差取最接近的_从零学DAX/Sql/Python030203SQL数据分类汇总续篇
- 深度学习:在图像上找到手势_使用深度学习的人类情绪和手势检测器:第1部分
- mac xampp连接mysql数据库_在mac上如何使用终端打开XAMPP自带的MySQL
- 客户和顾客是一个意思吗_履约保证金和投标保证金是一个意思吗?
- ipv6 6rd前缀计算
- uva 10098 Generating Fast(全排列)
- 技术大会值得参加吗?
- Oracle 字符串批量替换
- dlan android手机,电脑与手机远程互通八款DLNA安卓手机推荐
- 线性代数 第二章 矩阵 知识点总结(Jeff自我感悟)
- 组合数学在软件领域的运用
- 计算机毕业设计项目推荐 - 毕设开题选题
- evus是什么意思_美国签证和EVUS之间的区别是什么
- 试穿APP的NABCD
- 119全国消防日,我们要注意用火安全
- 基于PHP+MySQL音乐相册网站的设计与实现
- ArcGIS用土地利用数据导出shp
- 3d渲染服务器系统,3d渲染云服务器