详解单例模式线程安全
详解单例模式线程安全
单例模式有很多实现方法,饿汉、懒汉、静态内部类、枚举类,每种实现下获取单例对象(即调用 getInstance)时的保证线程安全
- 饿汉式:类加载就会导致该单实例对象被创建
- 懒汉式:类加载不会导致该单实例对象被创建,而是首次使用该对象时才会创建
实现1: 饿汉式
// 问题1:为什么加 final,防止子类继承后更改
// 问题2:如果实现了序列化接口, 还要做什么来防止反序列化破坏单例,如果进行反序列化的时候会生成新的对象,这样跟单例模式生成的对象是不同的。要解决直接加上readResolve()方法就行了,如下所示
public final class Singleton implements Serializable {// 问题3:为什么设置为私有? 放弃其它类中使用new生成新的实例,是否能防止反射创建新的实例?不能。private Singleton() {}// 问题4:这样初始化是否能保证单例对象创建时的线程安全?没有,这是类变量,是jvm在类加载阶段就进行了初始化,jvm保证了此操作的线程安全性private static final Singleton INSTANCE = new Singleton();// 问题5:为什么提供静态方法而不是直接将 INSTANCE 设置为 public, 说出你知道的理由。//1.提供更好的封装性;2.提供范型的支持public static Singleton getInstance() {return INSTANCE;}public Object readResolve() {return INSTANCE;}
}
实现2: 饿汉式
// 问题1:枚举单例是如何限制实例个数的:创建枚举类的时候就已经定义好了,每个枚举常量其实就是枚举类的一个静态成员变量
// 问题2:枚举单例在创建时是否有并发问题:没有,这是静态成员变量
// 问题3:枚举单例能否被反射破坏单例:不能
// 问题4:枚举单例能否被反序列化破坏单例:枚举类默认实现了序列化接口,枚举类已经考虑到此问题,无需担心破坏单例
// 问题5:枚举单例属于懒汉式还是饿汉式:饿汉式
// 问题6:枚举单例如果希望加入一些单例创建时的初始化逻辑该如何做:加构造方法就行了
enum Singleton {INSTANCE;
}
实现3:懒汉式
public final class Singleton {private Singleton() { }private static Singleton INSTANCE = null;// 分析这里的线程安全, 并说明有什么缺点:synchronized加载静态方法上,可以保证线程安全。缺点就是锁的范围过大,每次访问都会加锁,性能比较低。public static synchronized Singleton getInstance() {if( INSTANCE != null ){return INSTANCE;}INSTANCE = new Singleton();return INSTANCE;}
}
实现4:DCL 懒汉式(双重检验锁)
public final class Singleton {private Singleton() { }// 问题1:解释为什么要加 volatile ?为了防止重排序问题private static volatile Singleton INSTANCE = null;// 问题2:对比实现3, 说出这样做的意义:提高了效率public static Singleton getInstance() {if (INSTANCE != null) {return INSTANCE;}synchronized (Singleton.class) {// 问题3:为什么还要在这里加为空判断, 之前不是判断过了吗?这是为了第一次判断时的并发问题。if (INSTANCE != null) { // t2return INSTANCE;}INSTANCE = new Singleton();return INSTANCE;}}
}
实现5:静态内部类懒汉式
public final class Singleton {private Singleton() { }// 问题1:属于懒汉式还是饿汉式:懒汉式,这是一个静态内部类。类加载本身就是懒惰的,在没有调用getInstance方法时是没有执行LazyHolder内部类的类加载操作的。private static class LazyHolder {static final Singleton INSTANCE = new Singleton();}// 问题2:在创建时是否有并发问题,这是线程安全的,类加载时,jvm保证类加载操作的线程安全public static Singleton getInstance() {return LazyHolder.INSTANCE;}
}
详解单例模式线程安全相关推荐
- java 线程一直运行状态_详解JAVA 线程-线程的状态有哪些?它是如何工作的?
线程(Thread)是并发编程的基础,也是程序执行的最小单元,它依托进程而存在. 一个进程中可以包含多个线程,多线程可以共享一块内存空间和一组系统资源,因此线程之间的切换更加节省资源.更加轻量化,也因 ...
- Java多线程详解(线程不安全案例)
嗨喽-小伙伴们我又来了, 通过前面两章的学习,我们了解了线程的基本概念和创建线程的四种方式. 附上链接: 1. Java多线程详解(基本概念) 2. Java多线程详解(如何创建线程) ...
- ThreadPoolExecutor详解及线程池优化
前言 ThreadPoolExecutor在concurrent包下,是我们最常用的类之一.无论是做大数据的,还是写业务开发,对其透彻的理解以及如何发挥更好的性能,成为了我们在更好的coding道路上 ...
- java中断runnable_详解Java 线程中断
一.前言 大家肯定都使用过 Java 线程开发(Thread / Runnable),启动一个线程的做法通常是: new Thread(new Runnable( @Override public v ...
- Java高并发编程详解系列-线程上下文设计模式及ThreadLocal详解
导语 在之前的分享中提到过一个概念就是线程之间的通信,都知道在线程之间的通信是一件很消耗资源的事情.但是又不得不去做的一件事情.为了保证多线程线程安全就必须进行线程之间的通信,保证每个线程获取到的 ...
- java守护线程与用户线程_详解Java线程-守护线程与用户线程
干java 开发这么多年, 之前一直没留意java 进程还区分守护进程和用户进程.守护进程这个概念最早还是在linux系统中接触的,直到近期使用java开发心跳检测功能时,使用Timer时才发现原来j ...
- 一文详解java线程池 详解Java线程池的七个参数 详解池化技术 java如何选择核心线程数 详解Java线程池的拒绝策略
目录 引言 线程池使用场景 加快请求响应(响应时间优先) 加快处理大任务(吞吐量优先) 特殊说明 线程池的池化技术 线程池的创建 手动创建 创建newFixedThreadPool线程池 创建newS ...
- 图文详解 Java线程池
1.线程池的优势 (1)降低系统资源消耗,通过重用已存在的线程,降低线程创建和销毁造成的消耗: (2)提高系统响应速度,当有任务到达时,通过复用已存在的线程,无需等待新线程的创建便能立即执行: (3) ...
- java executors 详解_线程池—Executors 详解
各位志同道合的朋友们大家好,我是一个一直在一线互联网踩坑十余年的编码爱好者,现在将我们的各种经验以及架构实战分享出来,如果大家喜欢,就关注我,一起将技术学深学透,我会每一篇分享结束都会预告下一专题 线 ...
- Java线程详解(11)-线程池
Sun在Java5中,对Java线程的类库做了大量的扩展,其中线程池就是Java5的新特征之一,除了线程池之外,还有很多多线程相关的内容,为多线程的编程带来了极大便利.为了编写高效稳定可靠的多线程程序 ...
最新文章
- readonly时禁用删除键,readonly按删除键后页面后退解决方案
- (回文串)Manacher算法
- svn authz 授权文件模版
- 摆脱困境:在每种测试方法之前重置自动增量列
- phison主控ps3111量产工具_从固态硬盘拆解看门道 深入解读闪存编号和主控容量...
- 如何将mysql的数据库渲染到页面_vue.js实现数据库的JSON数据输出渲染到html页面功能示例...
- [BZOJ] 3231: [Sdoi2008]递归数列
- 测试交友软件哪个最好用,陌陌与比邻你觉得哪个好用?陌陌比邻两大交友软件对比...
- 关于微信中的localStorage及使用cookie的解决方案
- java比身高怎么做_D3 Y比例,y对比身高?
- python之集合操作 - |
- JQUERY-SELECT 实现下拉框可以搜索、选择
- 小米路由器 mini 重新刷回官方固件
- kafka内外网连接问题
- 鹏博士总经理陆榴遭免职 董事称事发突然
- bam获取序列_如何从BAM文件中提取fastq
- 如何调整DOSBox窗口大小
- 【Java Web基础】(五)实现新增下拉列表—由用户输入内容(Html+JS)
- 北京搬家货运公司汇总
- 美式看跌期权的二叉树定价