0

0

如何解决Java单例模式中的线程安全问题?

王林

王林

发布时间:2023-05-09 19:28:06

|

1719人浏览过

|

来源于亿速云

转载

    一. 使用多线程需要考虑的因素

    提高效率:使用多线程就是为了充分利用CPU资源,提高任务的效率线程安全:使用多线程最基本的就是保障线程安全问题

    所以我们在设计多线程代码的时候就必须在满足线程安全的前提下尽可能的提高任务执行的效
    故:
    加锁细粒度化:加锁的代码少一点,让其他代码可以并发并行的执行

    考虑线程安全:

    没有操作共享变量的代码没有安全问题
    对共享变量的读,使用volatile修饰变量即可
    对共享变量的写,使用synchronized加锁

    二. 单例模式

    单例模式能保证某个类在程序中只存在唯一一份实例,而不会创建出多个实例
    例如:DataSource(数据连接池),一个数据库只需要一个连接池对象

    单例模式分为饿汉模式和懒汉模式

    立即学习Java免费学习笔记(深入)”;

    1. 饿汉模式

    饿汉模式是在类加载的时候就创建实例
    这种方式是满足线程安全的(JVM内部使用了加锁,即多个线程调用静态方法,只有一个线程竞争到锁并且完成创建,只执行一次)

    实现代码:

    public class Singleton {
        private static Singleton instance = new Singleton();
        private Singleton(){
     
        }
        public static Singleton getInstance(){
            return instance;
        }
    }

    2. 懒汉模式

    懒汉模式是在类加载的时候不创建实例,第一次使用的时候才创建

    实现代码:

    public class Singleton {
        private static Singleton instance = null;
        private Singleton(){
     
        }
        public static Singleton getInstance(){
            if(instance == null){
                instance = new Singleton();
            }
            return instance;
        }
    }

    观察上述代码,在单线程下不存在线程安全问题,但是在多线程环境下存在安全问题吗? 

    分析:
    当实例没有被创建的时候,如果有多个线程都调用getInstance方法,就可能创建多个实例,就存在线程安全问题 
    但是实例一旦创建好,后面线程调用getInstance方法就不会出现线程安全问题

    结果:线程安全问题出现在首次创建实例的时候

    3. 懒汉模式(使用synchronized改进)

    我们使用sychronized修饰,????‍????️代码如下:

    public class Singleton {
        private static Singleton instance = null;
        private Singleton(){
     
        }
        public static synchronized Singleton getInstance(){
            if(instance == null){
                instance = new Singleton();
            }
            return instance;
        }
    }

    这样实现线程安全存在什么问题呢?

    解析:
    我们对方法使用synchronized修饰,也就是每次调用该方法的时候都会竞争锁,但是创建实例只需要创建一次,也就是创建实例后,再调用该方法还需要竞争锁释放锁

    结果:虽然满足线程安全,但是效率低

    4. 懒汉模式(使用双重校验锁改进)

    在上述代码的基础上进行改动:

    行业贸易网站管理系统 2007 Beta 1
    行业贸易网站管理系统 2007 Beta 1

    1.修正BUG站用资源问题,优化程序2.增加关键词搜索3.修改报价4.修正BUG 水印问题5.修改上传方式6.彻底整合论坛,实现一站通7.彻底解决群发垃圾信息问题。注册会员等发垃圾邮件7.彻底解决数据库安全9.修改交易方式.增加网站担保,和直接交易两中10.全站可选生成html.和单独新闻生成html(需要装组建)11. 网站有10中颜色选择适合不同的行业不同的颜色12.修改竞价格排名方式13.修

    下载

    使用双重if判定,降低竞争锁频率
    使用volatile修饰instance 

    实现代码:

    public class Singleton {
        private static volatile Singleton instance = null;
        private Singleton(){
     
        }
        public static synchronized Singleton getInstance(){
            if(instance == null){ //外层的if判断:如果实例被创建直接return,不让线程再继续竞争锁
                //在没有创建实例时,多个线程已经进入if判断了
                //一个线程竞争到锁,其他线程阻塞等待
                synchronized (Singleton.class) {
                    //内层的if判断,目的是让竞争失败的锁如果再次竞争成功的话判断实例是否被创建,创建释放锁return,没有则创建
                    if(instance == null){ 
                        instance = new Singleton();
                    }
                }
            }
            return instance;
        }
    }

    对双重if的解析:

    外层的if判断:实例只是被创建一次,当实例已经被创建好了就不要后续操作,直接return返回
    内层的if判断:实例未被创建时,多个线程同时竞争锁,只有一个线程竞争成功并创建实例,其他竞争失败的线程就会阻塞等待,当第一线程释放锁后,这些竞争失败的线程就会继续竞争,但是实例已经创建好了,所以需要再次进行if判断 

    画图分析,如下所示:

    Java单例模式中的线程安全问题怎么解决

    三. volatile的原理 

    volatile保证了可见性,有序性,在Java层面看,volatile是无锁操作,多个线程对volatile修饰的变量进行读可以并发并行执行,和无锁执行效率差不多

    volatile修饰的变量中,CPU使用了缓存一致性协议来保证读取的都是最新的主存数据 

    缓存一致性:如果有别的线程修改了volatile修饰的变量,就会把CPU缓存中的变量置为无效,要操作这个变量就要从主存中重新读取

    四. volatile的扩展问题(了解)

    如果说volatile不保证有序性,双重校验锁的写法是否有问题?

    关于new对象按顺序分为3条指令:

    (1) 分配对象的内存空间
    (2) 实例化对象
    (3) 赋值给变量

    正常的执行顺序为(1)(2)(3),JVM可能会优化进行重排序后的顺序为(1)(3)(2)

    这个重排序的结果可能导致分配内存空间后,对象还没有实例化完成,就完成了赋值
    在这个错误的赋值后,instance==null不成立,线程就会拿着未完成实例化的instance,使用它的属性和方法就会出错

    使用volatile保证有序性后:

    线程在new对象时不管(1)(2)(3)是什么顺序,后续线程拿到的instance是已经实例化完成的
    CPU里边,基于volatile变量操作是有CPU级别的加锁机制(它保证(1)(2)(3)全部执行完,写回主存,再执行其他线程对该变量的操作)

    热门AI工具

    更多
    DeepSeek
    DeepSeek

    幻方量化公司旗下的开源大模型平台

    豆包大模型
    豆包大模型

    字节跳动自主研发的一系列大型语言模型

    通义千问
    通义千问

    阿里巴巴推出的全能AI助手

    腾讯元宝
    腾讯元宝

    腾讯混元平台推出的AI助手

    文心一言
    文心一言

    文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

    讯飞写作
    讯飞写作

    基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

    即梦AI
    即梦AI

    一站式AI创作平台,免费AI图片和视频生成。

    ChatGPT
    ChatGPT

    最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

    相关专题

    更多
    c语言中null和NULL的区别
    c语言中null和NULL的区别

    c语言中null和NULL的区别是:null是C语言中的一个宏定义,通常用来表示一个空指针,可以用于初始化指针变量,或者在条件语句中判断指针是否为空;NULL是C语言中的一个预定义常量,通常用来表示一个空值,用于表示一个空的指针、空的指针数组或者空的结构体指针。

    236

    2023.09.22

    java中null的用法
    java中null的用法

    在Java中,null表示一个引用类型的变量不指向任何对象。可以将null赋值给任何引用类型的变量,包括类、接口、数组、字符串等。想了解更多null的相关内容,可以阅读本专题下面的文章。

    438

    2024.03.01

    if什么意思
    if什么意思

    if的意思是“如果”的条件。它是一个用于引导条件语句的关键词,用于根据特定条件的真假情况来执行不同的代码块。本专题提供if什么意思的相关文章,供大家免费阅读。

    775

    2023.08.22

    c++中volatile关键字的作用
    c++中volatile关键字的作用

    本专题整合了c++中volatile关键字的相关内容,阅读专题下面的文章了解更多详细内容。

    69

    2025.10.23

    线程和进程的区别
    线程和进程的区别

    线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

    502

    2023.08.10

    Python 多线程与异步编程实战
    Python 多线程与异步编程实战

    本专题系统讲解 Python 多线程与异步编程的核心概念与实战技巧,包括 threading 模块基础、线程同步机制、GIL 原理、asyncio 异步任务管理、协程与事件循环、任务调度与异常处理。通过实战示例,帮助学习者掌握 如何构建高性能、多任务并发的 Python 应用。

    166

    2025.12.24

    java多线程相关教程合集
    java多线程相关教程合集

    本专题整合了java多线程相关教程,阅读专题下面的文章了解更多详细内容。

    10

    2026.01.21

    C++多线程相关合集
    C++多线程相关合集

    本专题整合了C++多线程相关教程,阅读专题下面的的文章了解更多详细内容。

    14

    2026.01.21

    Python 自然语言处理(NLP)基础与实战
    Python 自然语言处理(NLP)基础与实战

    本专题系统讲解 Python 在自然语言处理(NLP)领域的基础方法与实战应用,涵盖文本预处理(分词、去停用词)、词性标注、命名实体识别、关键词提取、情感分析,以及常用 NLP 库(NLTK、spaCy)的核心用法。通过真实文本案例,帮助学习者掌握 使用 Python 进行文本分析与语言数据处理的完整流程,适用于内容分析、舆情监测与智能文本应用场景。

    10

    2026.01.27

    热门下载

    更多
    网站特效
    /
    网站源码
    /
    网站素材
    /
    前端模板

    精品课程

    更多
    相关推荐
    /
    热门推荐
    /
    最新课程
    Kotlin 教程
    Kotlin 教程

    共23课时 | 2.9万人学习

    C# 教程
    C# 教程

    共94课时 | 7.7万人学习

    Java 教程
    Java 教程

    共578课时 | 51.9万人学习

    关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
    php中文网:公益在线php培训,帮助PHP学习者快速成长!
    关注服务号 技术交流群
    PHP中文网订阅号
    每天精选资源文章推送

    Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号