多线程模式下的单例创建

2023-09-21 15:36:25

Java 单例
Doule Check 方式

/**
 * double check
 * 如果没有 synchronized 和 二次 checkNull 在单线程中没有任何问题。
 * synchronized 保证只能有一个线程进入方法体中,其他的线程会进入等待队列。
 * [_instance = new JavaTest()] 流程为: new 写入缓存 -> 更新到主存中,
 * 
 * 为了防止中间过程被打断需要为变量添加 volatile 
 * 
 * volatile 可以保证数据的可见行,即数据直接会更新更新到主存中,其他线程都可以看到。
 * 避免出现当前线程只是更新了缓存中的数据,而没有更新到主存中,在单例中就会导致其他线程再次创建实例,
 * 这样就违反了单例的本质。
 */
private static volatile JavaTest _instance;

public static JavaTest getInstance() {
    if (_instance == null) {
        synchronized (JavaTest.class) {
            if (_instance == null) {
                _instance = new JavaTest();
            }
        }
    }
    return _instance;
}
2. 根据classload原理直接创建静态实例
public class Singleton {  
    private static Singleton instance = null;  
    static {  
      instance = new Singleton();  
    }  
    private Singleton (){}  
    public static Singleton getInstance() {  
        return instance;  
    }  
} 
  1. 使用枚举的方式
    其实这种方式和上面的方式基本相同,枚举类在编译后其实也是把内部的每个枚举形成对应的静态实例,相比第一种double-check方式缺少了lazy load
static enum SingletonEnum {
    INSTANCE;

    private JavaTest javaTest;

    private SingletonEnum() {
        javaTest = new JavaTest();
    }

    public JavaTest getInstance() {
        return javaTest;
    }
}

public static JavaTest getInstance2() {
    return SingletonEnum.INSTANCE.getInstance();
}
  1. 使用静态内部类的方式,这种方式也可以实现懒加载(在Dagger和Hilt使用Singleton注入的类就是使用这种方式进行单例的实现的)
public class Singleton {  
    // 静态内部类
    private static class SingletonHolder {  
        private static final Singleton INSTANCE = new Singleton();  
    }  
    private Singleton (){}  
    
    public static final Singleton getInstance() {  
        return SingletonHolder.INSTANCE;  
    }  
}  

kotlin 单例

companion object {
    val instance: KotlinTest by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) {
        kotlinTest()
    }
}

lazy 可以实现懒加载

LazyThreadSafetyMode.SYNCHRONIZED 对应下面的方法:

private class SynchronizedLazyImpl<out T>(initializer: () -> T, lock: Any? = null) : Lazy<T>, Serializable {
    private var initializer: (() -> T)? = initializer
    // 这里同样适用了Volatile 来保持可见性
    @Volatile private var _value: Any? = UNINITIALIZED_VALUE
    // final field is required to enable safe publication of constructed instance
    private val lock = lock ?: this

    override val value: T
        get() {
            val _v1 = _value
            if (_v1 !== UNINITIALIZED_VALUE) {
                @Suppress("UNCHECKED_CAST")
                return _v1 as T
            }

            return synchronized(lock) {
                val _v2 = _value
                if (_v2 !== UNINITIALIZED_VALUE) {
                    @Suppress("UNCHECKED_CAST") (_v2 as T)
                } else {
                    val typedValue = initializer!!()
                    _value = typedValue
                    initializer = null
                    typedValue
                }
            }
        }

    override fun isInitialized(): Boolean = _value !== UNINITIALIZED_VALUE

    override fun toString(): String = if (isInitialized()) value.toString() else "Lazy value not initialized yet."

    private fun writeReplace(): Any = InitializedLazyImpl(value)
}
更多推荐

Layui快速入门之第十四节 分页

目录一:基本用法API渲染属性二:自定义主题三:自定义文本四:自定义排版五:完整显示一:基本用法分页组件laypage提供了前端的分页逻辑,使得我们可以很灵活处理不同量级的数据,从而提升渲染效率<!DOCTYPEhtml><html><head><metacharset="utf-8"><title>分页</title

STM32低功耗分析

1.ARM发布最新内核2023年5月29日,Arm公司今天发布了处理器核心:Cortex-X4、Cortex-A720和Cortex-A520。这些核心都是基于Armv9.2架构,只支持64位指令集,不再兼容32位应用。Arm公司表示,这些核心在性能和效率方面都有显著的提升,同时也加强了安全性和可扩展性。Cortex-

字符串相似度算法

相似度算法JaccardSimilarityCoefficient、JaroWinkler、CosineSimilarity、Levenshtein距离编辑算法案例。Jaccard相似性系数衡量两个集合的相似程度,通过计算两个集合的交集大小除以并集大小得出。适用于处理文本、推荐系统、生物信息学等领域CosineSimi

青龙面板从0到1的实现

文章目录需要有一台云服务器Docker、SSH、青龙如何打开云服务器上的青龙面板青龙注册登录看这个青龙配置最后、从此需要有一台云服务器我这里选择的是阿里云新用户免费送的三个月服务器,服务器操作系统:CenOS(其他操作系统也可以:Ubantu、Debian)。Docker、SSH、青龙为云服务器系统安装Docker容器

支付功能、支付平台、支持渠道如何测试?

有学员提问:作为一个支付平台,接入了快钱、易宝或直连银行等多家的渠道,内在的产品流程是自己的。业内有什么比较好的测试办法,来测试各渠道及其支持的银行通道呢?作为产品,我自己办了十几张银行卡方便测试,但QA和开发不愿意这样做,怎么办呢?回答:对支付平台而言,与支付渠道相关的测试大致可以分为:测试支付渠道功能、测试支付产品

scons体验以及rtthread中的简单使用

SCons是一个用于构建软件项目的软件构建工具。它使用Python脚本作为配置文件,提供了一种简单而灵活的方式来描述软件项目的构建过程。下面是一个简单的SCons使用示例:安装SCons:首先,确保你已经安装了Python。然后,可以使用Python的包管理器pip安装SCons。在命令行中运行以下命令安装SCons:

【谢希尔 计算机网络】第2章 物理层

目录通信基础基本概念两个公式lim奈氏准则香农定理奈氏准则VS香农定理编码与调制​编辑物理层下面的传输媒体导引型传输媒体1.双绞线2.同轴电缆3.光缆非导引型传输媒体无线电微波通信卫星通信无线局域网使用的ISM频段信道复用技术频分复用、时分复用和统计时分复用波分复用码分复用CDMA工作原理CDMA的重要特点数字传输系统

01Spring的Ioc思想和依赖注入手段(DI)

传统方式创建对象的缺陷连接MySQL实现登录功能控制层UserControllerpublicclassUserController{//多态,半面向接口编程privateUserServiceuserService=newUserServiceImpl();publicvoidlogin(){Stringuserna

怒刷LeetCode的第10天(Java版)

目录第一题题目来源题目内容解决方法方法一:两次拓扑排序第二题题目来源题目内容解决方法方法一:分治法方法二:优先队列(PriorityQueue)方法三:迭代第三题题目来源题目内容解决方法方法一:迭代方法二:递归方法三:双指针方法四:栈第一题题目来源2603.收集树中金币-力扣(LeetCode)题目内容解决方法方法一:

HashMap:Java中的高性能键值对存储

一、前言HashMap是Java中最常用的数据结构之一,用于存储键值对,提供了快速的数据检索和插入操作。本文将深入探讨HashMap的内部原理、用法、常见面试问题以及源码分析。二、HashMap的内部工作原理2.1哈希表HashMap的核心是哈希表,它是一个数组,用于存储键值对。哈希表的每个位置称为"桶",每个桶可以存

Http和Https

Http和Https1.URI和URLURI(UniformResourceIdentifier):统一资源标识符,标识资源,可以是相对路径也可以绝对路径表示。绝对路径:http://www.example.com/images/logo.png相对路径:/image/logo.pngURL(UniformResour

热文推荐