首页 > 其他分享 >线程安全的单例模式

线程安全的单例模式

时间:2022-11-04 14:09:10浏览次数:62  
标签:Singleton getInstance singleton private 线程 模式 单例 static public


懒汉式

加方法锁

public class Singleton {
private static Singleton singleton = null;

private Singleton() {
}

public static synchronized Singleton getInstance() {
if (Objects.isNull(singleton)) {
singleton = new Singleton();
}
return singleton;
}
}
  1. 直接在 getInstance() 方法加锁,但是加锁的范围太大,性能低下

双重检查锁定

public class Singleton {
private static volatile Singleton singleton = null;

private Singleton() {
}

public static Singleton getInstance() {
// 1
if (Objects.isNull(singleton)) {
synchronized(Singleton.class) {
if (Objects.isNull(singleton)) {
// 2
singleton = new Singleton();
}
}
}
return singleton;
}
}

对象需要加volatile 关键字,主要是防止指令重排序。​​singleton = new Singleton();​​方法在执行的时候有三个指令:

memory = allocate();  // 1:分配对象的内存空间 ctorInstance(memory); // 2:初始化对象 instance = memory;  // 3:设置instance指向刚分配的内存地址

当线程A获取到锁,执行初始化的时候发生了指令重排,1->3->2。当2还没有被执行时,线程B执行到代码标记1的位置,这时判断到对象不为空,直接返回该对象,但是这个时候该对象可能还并没有完成初始化,导致线程B在执行过程中抛错。

静态内部类

public class Singleton {
private static class LazyHolder {
private static final Singleton INSTANCE = new Singleton();
}

private Singleton() {
}

public static Singleton getInstance() {
return LazyHolder.INSTANCE;
}
}

既实现了线程安全,又避免了同步带来的性能影响。JVM在类的初始化阶段(即在Class被加载后,且被线程使用之前),会执行类的初始化。在 执行类的初始化期间,JVM会去获取一个锁。这个锁可以同步多个线程对同一个类的初始化。使用这种方式,我们是允许​​new Singleton();​​过程发生指令重排的。

使用枚举的形式

public class EnumSingleton {
private EnumSingleton() {
}

public static EnumSingleton getInstance() {
return Singleton.INSTANCE.getInstance();
}

private enum Singleton {
INSTANCE(new EnumSingleton());
private EnumSingleton singleton;

//JVM会保证此方法绝对只调用一次
Singleton(EnumSingleton singleton) {
this.singleton = singleton;
}

public EnumSingleton getInstance() {
return singleton;
}
}
}

JVM会保证枚举类构造方法绝对只调用一次,所以保证了对象实例的唯一性

饿汉式

public class Singleton {
private static final Singleton singleton = new Singleton();

private Singleton() {
}

public static Singleton getInstance() {
return singleton;
}
}


标签:Singleton,getInstance,singleton,private,线程,模式,单例,static,public
From: https://blog.51cto.com/u_15861563/5823698

相关文章

  • Java线程状态详解
    Java的每个线程都具有自己的状态,Thread类中成员变量threadStatus存储了线程的状态: privatevolatileintthreadStatus=0; 在Thread类中也定义了状态的枚举,共六......
  • SpringCloud(六) - RabbitMQ安装,三种消息发送模式,消息发送确认,消息消费确认(自动,手动)
    1、安装erlang语言环境1.1创建erlang安装目录mkdirerlang1.2上传解压压缩包上传到:/root/解压缩#tar-zxvfotp_src_22.0.tar.gz1.3进入解压缩目录,指定......
  • Java守护线程
    Java中,通过Thread类,我们可以创建2种线程,分为守护线程和用户线程。守护线程是所有非守护线程的保姆,当所有非守护线程执行完成或退出了,即使还有守护线程在运行,JVM也会直接退......
  • BIOS三种硬盘模式
    文章目录​​IDE模式​​​​RAID模式​​​​AHCI模式​​IDE模式IDE表示硬盘的传输接口,我们常说的IDE接口,也叫ATA(AdvancedTechnologyAttachment)接口,现在PC机使用的硬盘......
  • Rocksdb 的优秀代码(三)-- 工业级 线程池实现分享
    文章目录​​前言​​​​1.Rocksdb线程池概览​​​​2.Rocksdb线程池实现​​​​2.1基本数据结构​​​​2.2线程池创建​​​​2.3线程池调度线程执行​​​​2.......
  • 关于 线程模型中经常使用的 __sync_fetch_and_add 原子操作的性能
    最近从kvell这篇论文中看到一些单机存储引擎的优秀设计,底层存储硬件性能在不远的未来可能不再是主要的性能瓶颈,反而高并发下的CPU可能是软件性能的主要限制。像BPS/AEP/Op......
  • TDengine:无模式写入行协议的四种方式
    小T导读:为了在数据采集项频繁变动的情况下保证用户仍然能够顺利地完成数据记录工作,TDengine 提供了三种无模式写入协议,分别是InfluxDBLine协议、OpenTSDB Telnet协......
  • 初识设计模式 - 备忘录模式
    简介备忘录设计模式(MementoDesignPattern)也叫作快照(Snapshot)模式,主要用于实现防丢失、撤销、恢复等功能。其定义是,在不违背封装原则的前提下,捕获一个对象的内部状态,并......
  • WINDOWS启动模式
    一、WINDOWS启动需要首先进入BIOS,BIOS全称为BasicInputOutputSystem,基本输入输出系统,传统的BIOS即LegacyBIOSBIOS的目的主要有五个:  1、检测硬件,检测硬件能否正常......
  • 设计模式:责任链模式的应用场景及源码应用
    一、概述责任链模式(ChainofResponsibilityPattern)是将链中每一个节点看作是一个对象,每个节点处理的请求均不同,且内部自动维护一个下一节点对象。当一个请求从链式的首......