解决多线程环境下单例模式同时访问生成多个实例

这篇具有很好参考价值的文章主要介绍了解决多线程环境下单例模式同时访问生成多个实例。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

在多线程环境下使用单例模式可能会出现线程安全问题,还有延迟加载问题,这些问题在设计之初需要考虑,保证项目生产上线不影响正常使用

目录

前言

正文

如何满足单例:1.构造方法是private、static方法、if语句判断

解决多线程环境下单例模式问题方法:懒汉式加锁、双重检查锁定、静态内部类或枚举类登方法

①、单线程

出现的问题:

②、多线程

出现的问题:

解决方案:

③、多线程单例——单锁

出现的问题:

④、多线程——双重锁(Double-Check Locking)


正文

如何满足单例:1.构造方法是private、static方法、if语句判断

解决多线程环境下单例模式问题方法:懒汉式加锁、双重检查锁定、静态内部类或枚举类登方法

①、单线程

Single类

//Single类,定义一个GetInstance操作,允许客户访问它的唯一实例。GetInstance是一个静态方法,主要负责创建自己的唯一实例
public class LazySingleton {
    private static LazySingleton instance;

    private LazySingleton() {
        System.out.println("创建一次");
    }

    public static LazySingleton GetInstance() {
        //当多线程来临的时候判断是否为null,此时instance就是临界资源,会实例化多个
        if (instance == null) {
            instance = new LazySingleton();
        }
        return instance;
    }
}
//客户端代码
public class Main {
    public static void main(String[] args) {
            LazySingleton s1= LazySingleton.GetInstance();
            LazySingleton s2=  LazySingleton.GetInstance();

            if(s1==s2){
                System.out.println("两个对象是相同的实例");
            }
    }
}

运行结果:

解决多线程环境下单例模式同时访问生成多个实例,单例模式,java,android

出现的问题:

这样的话就满足了单例的效果,保证只实例化一个类,因为LazySingleton封装它的唯一实例,这样它可以严格地控制客户怎样访问它以及何时访问它。简单地说就是对唯一实例的受控访问。客户端通过那唯一可以访问的GetInstance方法来访问那一个实例。但如果是多个线程同时调用GetInstance方法,同时运行到了GetInstance方法这儿,它们都会去判断有没有被实例化,判断都为True,那样的话就创建了两个实例,就违背了单例模式,不是一个单例。看下多线程下的单例:

②、多线程

单例类

public class LazySingleton {
    private static LazySingleton instance;

    private LazySingleton() {
        System.out.println("创建一次");
    }

    public static LazySingleton GetInstance() {
        //当多线程来临的时候判断是否为null,此时instance就是临界资源,会实例化多个
        if (instance == null) {
            instance = new LazySingleton();
        }
        return instance;
    }
}

main函数

public class Main {
    public static void main(String[] args) {
        Runnable r=()->{

            LazySingleton s1= LazySingleton.GetInstance();
            LazySingleton s2=  LazySingleton.GetInstance();

            if(s1==s2){
                System.out.println("两个对象是相同的实例");
            }
        };

        //两个线程
        Thread t1= new Thread(r);
        Thread t2= new Thread(r);

        t1.start();
        t2.start();
    }
}

运行结果:

解决多线程环境下单例模式同时访问生成多个实例,单例模式,java,android

出现的问题:

我们会发现对象被创建了两次,我们通过调试发现s1和s2两个对象的地址实际上是不一样的:

解决多线程环境下单例模式同时访问生成多个实例,单例模式,java,android

当线程t1刚执行完if (instance == null)判断之后时间片到了,t2线程执行完if (instance == null)判断之后就进入方法体生成了实例,此时t1线程又获得了时间片,t1会接着上次中断的地方继续执行,t1线程便会进入方法体又生成了一个新的实例,此时t1和t2线程各生成了一个实例

解决方案:

如何解决这样一个问题呢?

添加锁,当线程位于临界区的时候就上锁,其他线程来临的时候只能在外排队等待。

③、多线程单例——单锁

单例类

package com.example;

public class LazySingleton {
    private static LazySingleton instance;

    private LazySingleton() {
        System.out.println("创建一次");
    }

    public static LazySingleton GetInstance() {
        //当多线程来临的时候判断是否为null,此时instance就是临界资源,会实例化多个
        //方法:加锁-把判断的这部分逻辑上锁
        synchronized ("") {
            if (instance == null) {
                instance = new LazySingleton();
            }
        }
        return instance;
    }

}

main函数

public class Main {
    public static void main(String[] args) {
        Runnable r=()->{

            LazySingleton s1= LazySingleton.GetInstance();
            LazySingleton s2=  LazySingleton.GetInstance();

            if(s1==s2){
                System.out.println("两个对象是相同的实例");
            }
        };

        //两个线程
        Thread t1= new Thread(r);
        Thread t2= new Thread(r);

        t1.start();
        t2.start();
    }
}

运行结果:

解决多线程环境下单例模式同时访问生成多个实例,单例模式,java,android

出现的问题:

发现对象创建了一次。在同一时刻加了锁的那部分程序只有一个线程可以进入,我们可以让最先进入的那个线程先上一把锁,创建实例。后面在进入的线程就不会再去创建对象实例了,因为第一名来的线程已经创建了,你这个判断的结果是False,自然无法创建了。这样的话就保证了多个线程同时访问的话不会有多个实例化。解决了上面单实例带来的问题。但每次进入的线程都需要先加锁在判断,我都还不知道有没有创建过这个实例呢你就让我加锁,第一名已经实例化过了,我进去再加锁,在判断一次,如果有上百个线程同时访问呢,这样的工作重复上百次,不是很影响我这个程序的性能吗?我们就可以用到双重锁定来解决这个问题

④、多线程——双重锁(Double-Check Locking)

package com.example;

public class DoubleLockSingleton {
    private static DoubleLockSingleton instance;

    private DoubleLockSingleton() {
        System.out.println("实例化了一次");
    }

    public static DoubleLockSingleton GetInstance() {
        //第一层判断:先判断实例是否存在,不存在再加锁处理
        if (instance == null) {
            synchronized ("") {
                //第二层判断
                if (instance == null) {
                    instance = new DoubleLockSingleton();
                }
            }
        }
        return instance;
    }
}

通过这样两重的判断,进入的线程不用每次都加锁,只是在实例未被创建的时候在加锁处理。同时也保证多线程的安全。

解决多线程环境下单例模式同时访问生成多个实例,单例模式,java,android

 

选择哪种多线程环境下的单例模式解决方案应根据具体需求来决定。如果对线程安全和延迟加载有较高要求,可以选择懒汉式加锁、双重检查锁定或静态内部类的方式;如果对性能要求较高且不需要延迟加载,可以选择饿汉式的方式;如果希望代码简洁易读,可以选择枚举类的方式文章来源地址https://www.toymoban.com/news/detail-621342.html

到了这里,关于解决多线程环境下单例模式同时访问生成多个实例的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • macOS搭建PHP开发环境(brew安装nginx、mysql 和多版本php,并配置多个php同时运行的环境)

    由于homebrew主库中没有PHP7.2 之前的版本,并且7.2,7.3版本也被标记成过时版本;所以需要先挂在第三方的扩展,具体操作如下: php5.6 php7.3 php7.4 php8.2 默认新版8以上直接安装 sudo vim /usr/local/etc/php/5.6/php-fpm.conf  下的: 注意:5.6版本的配置文件路径和其他版本不一样 listen = 127

    2024年02月04日
    浏览(68)
  • 前端请求队列,解决多个请求同时请求一个接口导致阻塞的问题

    最近开发的数据大屏项目,使用echarts图表,通过拖拽的方式完成大屏的布局。 每一个图表编写一个vue文件,例如柱状图(barChart.vue): queryEchartsData的方法体如下: 折线图等其他图表同理,都是使用queryEchartsData来获取后端接口返回的数据,queryEchartsData写在queryData.js中,然后

    2024年01月20日
    浏览(44)
  • 【JAVA开发面试】如何处理并发访问如何进行代码的单元测试Java多线程编程消息中间件设计模式技术难题是如何解决的

    【 点我-这里送书 】 本人详解 作者:王文峰,参加过 CSDN 2020年度博客之星,《Java王大师王天师》 公众号:JAVA开发王大师,专注于天道酬勤的 Java 开发问题 中国国学、传统文化和代码爱好者的程序人生,期待你的关注和支持!本人外号:神秘小峯 山峯 转载说明:务必注明

    2024年02月03日
    浏览(52)
  • 解决selenium访问网页中多个iframe,导致无法锁定元素的问题

    获取全部的iframe列表 调试获取目标iframe 使用: browser.switch_to.frame(目标iframe) 退回到原有的状态: browser.switch_to.default_content() 不同的iframe之间的元素无法被selenium锁定,因此需要通过人为调试,得到具体的iframe窗口,进入目标iframe后才能够进行元素的锁定,锁定后就得到目标

    2024年02月22日
    浏览(49)
  • 淘宝无痕下单生成器一拖多入口生成器(附api生成接口以代码)

    淘宝无痕下单生成器的用途是:通过无痕下单生成器生成的二维码,用户通过扫码直接无痕下单的,电商后台只显示成交,但是没有路径,什么都没有,没有痕迹,即使通过淘宝生意参谋流量路径、访客人数等数据都无法显示。可快速带动搜索权重,获得

    2024年02月12日
    浏览(150)
  • 如何同时启动多个cmd命令?

    在windows的命令行中,如果要执行多个启动命令,就需要打开多个cmd命令窗口。这时候就可以使用批处理命令,在执行命令的目录中新建一个startup.bat文件,右击记事本打开 填写需要执行的命令,每一个命令前加start ,这时候就会启动一个新的cmd窗口 比如要启动hub 、node  保存

    2024年02月11日
    浏览(47)
  • Logstash同时运行多个配置文件

    创建存放logstash配置文件存放目录 修改pipelines.yml进行配置 把所有的配置文件放到 conf.d 目录下面 运行logstash时会读取 conf.d 目录下所有以.conf 结尾的文件 直接运行 不需要指定 -f 参数了

    2023年04月18日
    浏览(39)
  • linux文件锁(保证只能同时启动一个实例,不同时启动多个实例)

    可以使用Linux中的进程锁来实现只能启动一个实例的功能。一种常见的方法是使用文件锁(File Locking)。 可以在程序启动时创建一个特定的文件,并尝试对该文件进行加锁。如果加锁成功,则表示程序是第一个实例,可以继续执行。如果加锁失败,则表示已经有一个实例在运

    2024年02月16日
    浏览(56)
  • ffmpeg——同时剪辑多个视频并合并

    基本语法 所用的ffmpeg的语法: 1.剪辑单个视频 ffmpeg -i [2021-11-24-1-2.mp4] -vcodec copy -acodec copy -ss [00:00:00] -to [00:00:05] [output/p3.mp4][ ]中三个参数依次为:剪辑视频源文件;第一个时间为剪辑的起始时间;第二个时间为视频持续的时间长度; 剪辑好的文件名 2.合并视频片段 ffmpeg -

    2024年02月16日
    浏览(43)
  • Element 多个Form表单 同时验证

    在一个页面中需要实现两个Form表单,并在页面提交时需要对两个Form表单进行校验,两个表单都校验成功时才能提交 所用技术栈:Vue2+Element UI 注意项: 两个form表单,每个表单上都设置单独的model和ref,不能同时使用,否则每个表单上的校验提示会失效 最后,👏👏 😀😀😀

    2024年02月07日
    浏览(44)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包