首页 > 其他分享 >多线程|饿汉模式和懒汉模式

多线程|饿汉模式和懒汉模式

时间:2023-09-02 18:26:00浏览次数:57  
标签:模式 instance 实例 static 饿汉 多线程 懒汉

单例模式是只有单个实例的模式,应用在只能有一个实例的场景中。单例模式有很多种,这里介绍饿汉模式和懒汉模式两个单例。

一、饿汉模式

“饿汉”是一种形象的描述,“饿汉”看到吃的就非常急切,把这种急切的形象类比到Java中就是在类加载阶段就把实例创建出来了。什么是类加载?Java代码中的每个类,都会在编译完成之后得到.class文件,JVM中就会加载这个.class文件,读取其中的二进制指令,并且构造出对应的对象,这就是类加载。

实现饿汉模式:

static是实现饿汉模式的核心,static可以用来修饰成员变量和方法和成员方法,被修饰的成员变量和成员方法不依赖实例去访问,只要类被加载,通过类名就可以直接访问。由于被static修饰的成员变量和成员方法不依赖实例去访问,那么就不会因为实例的多次创建而产生多份数据,被static修饰的变量或成员在内存中只存在一份。

代码实现:

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

 

分析上述代码实例的唯一性:instance被static修饰,让instance具有类属性,在类加载之后instance在内存中只存在一份,同样的static修饰getInstance()方法,每次通过类名访问这个方法时,访问的都是同一份数据,通过这个方法得到的instance也是同一份数据,这样保证了实例的唯一性,同时,构造方法使用private修饰,保证在该类之外的代码中都不能创造新实例。

二、懒汉模式

与“饿汉模式”一样,“懒汉”也是形象的描述,与“饿汉”在类加载就创建实例不同,“懒汉”是在第一次需要的时候才创建实例。

代码是实现:

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

懒汉模式保持实例唯一性与饿汉模式相同。

我们上述讨论的只是饿汉模式与懒汉模式怎么创建,那么多线程环境下,这两个线程是否具有线程安全问题呢?

先来看看饿汉模式

 

 饿汉模式在类加载阶段就创建好实例,多线程环境下,只涉及读操作,因此,饿汉模式多线程环境下是安全的。

 懒汉模式创建实例是在第一次使用时才创建,涉及到读和写,因此懒汉模式多线程下是不安全的。

 以上就是线程不安全的一种情况。那么如何将懒汉模式变成线程安全的呢?首先第一步是加锁,保证创建实例的过程是具有原子性的,进行如下操作:

 上述的加锁操作是让写和读具有原子性,此时多个线程要进行读和写的操作就必须等到锁被释放。上面说过,懒汉模式是第一次使用的时候需要创建实例,后面的使用就不要创建实例了,但是上述代码每次获取instance都要进行加锁操作,而加锁操作是非常消耗资源的,其实只需要在第一次创建出对象之前加锁,其他时候是没有必要的,因此,可以再给代码加上一个判定,判定instance是否为空,为空加锁创建,不为空直接返回instance。

 代码写到这,其实还存在一个问题没有考虑,那就是内存可见性问题,由于JVM的优化,只有第一次是将内存中的值读到寄存器中,而且编译器还会进行重排序。

 new操作分以下三步:

1、申请内存空间

2、调用构造方法,把内存空间初始化成一个合理的对象

3、把内存空间的地址给instance使用

正常情况下,是按照123的顺序来执行的,但是编译器会进行指令重排序来提高效率,所以new操作的顺序会被打乱,此时也会存在线程安全问题,解决办法是加上volatile关键字。

最终代码:

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

 

标签:模式,instance,实例,static,饿汉,多线程,懒汉
From: https://www.cnblogs.com/xbyss/p/17672601.html

相关文章

  • 【从互联网商业思维的角度分析商业模式在国内各大互联网产品的运用】
    随着互联网技术的不断进步,互联网商业模式也在不断变化,各个互联网企业都在不断尝试各种商业模式,以满足不同消费者群体的需求,提高企业营销效益,下面我们将从互联网商业思维的角度,分析一下商业模式在国内各大互联网产品的运用。一、电商模式电商模式是指在互联网上建立电子商务平台,通......
  • mongodb副本集(非仲裁模式)修改各节点ip(update方式)
    环境:OS:Centos7mongodb:5.0当前的ip变更后的ip192.168.1.108192.168.1.105   PRIMARY192.168.1.109192.168.1.106   SECONDARY192.168.1.110192.168.1.107   SECONDARY 1.查看当前的集群登录一个节点上查......
  • 【23种设计模式】单例模式(一)
    前言:单例模式是创建型模式5种中的第1种,关注对象的创建,保证一个类仅有一个实例,并且提供一个全局访问点。在软件系统中,经常有这样一些特殊的类,必须保证它们在系统中只存在一个实例,才能确保它们的逻辑正确性、以及良好的效率。如何绕过常规的构造器,提供一种机制来保证一个类只创建一......
  • Flink 1.17教程:Standalone会话模式运行时架构及并行度
    运行时架构——Standalone会话模式为例并行度并行度是指在计算过程中同时执行多个任务或操作的能力。在ApacheFlink中,并行度是指同时执行作业中的多个任务或算子的能力。并行度的引入是为了解决以下问题:提高计算速度:通过将任务拆分成多个子任务,并行执行它们,可以大大提高计算速度......
  • Flink 1.17教程:Hadoop yarn会话运行模式
    YARN运行模式_环境准备YARN上部署的过程是:客户端把Flink应用提交给Yarn的ResourceManager,Yarn的ResourceManager会向Yarn的NodeManager申请容器。在这些容器上,Flink会部署JobManager和TaskManager的实例,从而启动集群。Flink会根据运行在JobManger上的作业所需要的Slot数量动态分配T......
  • Flink 1.17教程:部署模式介绍及Standalone运行模式
    部署模式介绍在一些应用场景中,对于集群资源分配和占用的方式,可能会有特定的需求。Flink为各种场景提供了不同的部署模式,主要有以下三种:会话模式(SessionMode)、单作业模式(Per-JobMode)、应用模式(ApplicationMode)。它们的区别主要在于:集群的生命周期以及资源的分配方式;以及应用的mai......
  • Flink 1.17教程:Hadoop yarn运行模式——单作业模式和应用模式
    YARN运行模式_单作业模式单作业模式部署(1)执行命令提交作业YARN运行模式_应用模式应用模式同样非常简单,与单作业模式类似,直接执行flinkrun-application命令即可。如:bin/flinkrun-application-tyarn-application-ccom.atguigu.wc.WordCountStreamUnboundedDemo./FlinkTutorial......
  • Flink 1.17教程:集群搭建、运行模式(standalone/yarn/k8s)及历史服务器
    集群角色集群启动如果是部署在本地,本地访问,无需进行任何配置,直接启动即可。如果是部署在服务器,需要远程访问,则需要将flink.conf中的localhost修改为服务器IP地址或是0.0.0.0节点服务器hadoop102hadoop103hadoop104角色JobManagerTaskManagerTaskManagerTaskManager[atguigu@node001......
  • Redis队列Stream&Redis多线程详解(8)
    Redis目前最新版本为Redis-6.2.6,考虑到实际的情况,本次课程会以CentOS7下Redis-6.2.4版本进行讲解。下载地址:https://redis.io/download安装运行Redis很简单,在Linux下执行上面的4条命令即可,同时前面的课程已经有完整的视频讲解,请到网盘中下载观看,并自行安装。如安装过程出......
  • 230901 简单模式,避免贪婪
    短线操作中,存在各种各样的模式与上涨方式.比如德赛西威的机构缓慢上涨, 星期六,中贝,金科股份,直接快速上涨.美丽生态,金盛控股,人民网的震荡上涨方式.多种上涨方式,则存在多种的买入位置与,买点与卖点.你要想把这些所有的都覆盖,显然是不可能的.比如,掌握打板,掌握半路,......