当前位置: 首页 > article >正文

javaEE-多线程案例-单例模式

目录

啥是设计模式?

一.饿汉式

实现步骤:

二.懒汉式

实现步骤:

三、懒汉式优化1

四.懒汉式优化2

五.懒汉式优化3

总代码:


单例模式是一种设计模式。

啥是设计模式?

设计模式好⽐象棋中的"棋谱".红⽅当头炮,⿊⽅⻢来跳.针对红⽅的⼀些⾛法,⿊⽅应招的时候有⼀ 些固定的套路.按照套路来⾛局势就不会吃亏。软件开发中也有很多常⻅的"问题场景".针对这些问题场景,⼤佬们总结出了⼀些固定的套路.按照这个套路来实现代码,也不会吃亏。

单例模式能够保证在线程中只创建唯一一份实例,不会创建出多份实例。

一.饿汉式

类加载的同时,创建实例。

实现步骤:

1.在类内实例化一个 私有,静态 的该类实例。

2.将构造器私有化。

3.提供一个公共的方法,返回该类的实例化对象。

代码展示:


/**
 *  //单例模式
 *    饿汉式
 */
class Instance{
    //1.实例化Instance线程,将其设为私有,静态
    private static Instance single=new Instance();
    //2.私有化构造器
    private Instance(){
    }
    //3.提供公共方法,返回类内创建的实例对象
    public static Instance getInstance(){
        return single;
    }
}

二.懒汉式

类加载的时候不会创建实例,第一次使用的时候才创建实例.

实现步骤:

1.创建私有,静态该类对象single,并设为null.

2.将构造器私有化。

3.提供公共方法,判断该类是否已经被创建,若single=null,则实例化对象,否则,直接返回single实例。

代码展示:

class InstanceLazy1{
    // 1.创建该类对象,设为私有,静态
    // 先不实例化 将其设为null
    private static InstanceLazy1 single=null;
    //2.将构造器私有化
    private InstanceLazy1(){}
    //3.提供公共的方法,判断该类是否被实例化过
    //若未被实例化,则实例化对象,
    //否则直接返回single
    public static InstanceLazy1 getInstance(){
        if(single==null){
            single=new InstanceLazy1();
        }
        return single;
    }
}

三、懒汉式优化1

在单线程下,懒汉式是线程安全的,但是若是在多线程下,懒汉模式就可能出现线程安全问题。

在两个线程t1,t2下:

为防止在多线程下,创建出多个对象,要使用synchronized锁,将if和new打包成一个原子的,在判断之前,先上锁,这样就能避免在第一次创建对象的时候,引发线程安全问题。

(这里创建多个对象虽然不会出现异常,无实质性错误,但是若创建的对象占用的内存空间是巨大的,此时若创建多个,就会带来非常大的代价,甚至有可能使内存满,)

(return new InstanceLazy1(),这里写错了

但是,加锁之后,每次判断该类是否已被创建,都要先上锁,这势必会降低代码的运行效率,且可能出现 线程安全 只可能发生在第一次要创建对象的时候。

四.懒汉式优化2

为提高效率,在上锁之前,先判断是否是否创建过对象。若未创建,再上锁,再次判断是否实例化了对象。注意两次判断的作用是不同的。

第一次判断是为了提高代码执行效率,第二次是判断是否已创建对象。

五.懒汉式优化3

指令重排序问题也有可能引发线程安全问题.

指令重排序:代码优化的一种方式,调整代码的执行顺序,在原来逻辑不变的前提下,提高代码的执行效率。

可以使用volatile关键字来避免底层自动进行指令重排序.

懒汉式可能发生指令重排序问题是在创建对象的时候:

创建对象,分为三步:

1.申请一段内存空间

2.在这个内存上调用构造方法,创建出这个实例

3.将这个内存地址赋给single引用变量.

正常情况下,是按照1 2 3 来执行的,但有时会按照1 3 2来执行,也能创建出实例对象,这就是指令从排序.

但是在多线程下,若按照1 3 2来执行 就会引发线程安全问题.

这里,在代码重排序后创建出来的single对象,属于未初始化的全“0”值,若该对象中有属性或方法,一旦在后面的代码使用该对象,就可能会报错!!!

在single对象处加上volatile关键字修饰,就能禁止代码重排序,防止这样的对象被创建,解决线程安全问题。

总代码:

/**
    单例模式
    懒汉式
/
class Instance{
    //1.实例化Instance线程,将其设为私有,静态
    private static Instance single=new Instance();
    //2.私有化构造器
    private Instance(){
    }
    //3.提供公共方法,返回类内创建的实例对象
    public static Instance getInstance(){
        return single;
    }
}

/**
 * 单例模式
 * 饿汉式 优化版
 */
class InstanceLazy{
    // 定义该类对象,设为私有,静态
    // 先不实例化对象 将其设为null

    //优化3:为防止出现 指令重排序问题, 防止出现线程安全问题
    // 给single对象 加volatile关键字,底层不再进行指令重排序
    private static volatile InstanceLazy single=null;
    //将构造器私有化
    private InstanceLazy(){}
    //提供获取对象的公共方法,在方法内创建对象
    public static InstanceLazy getInstance(){
        Object locker=new Object();
        //判断
        // 若还未实例化对象,就实例化对象,
        if(single==null){//优化2:当第一次创建后,之后就不用再判断了,也就不用再加锁了,
                        //为了提高代码的效率,先判断一下,若不为空,则不再加锁,直接返回对象
            synchronized(locker){//懒汉式 优化1 :为防止出现线程安全问题
                                //将判断为空和创建新线程,设置为一个 原子的
                if(single==null){
                    single=new InstanceLazy();
                }
            }
        }
        //若已创建过对象,就直接返回创建过的对象
        return single;
    }
}
/**
    测试用例
/
public class Thread{
    public static void main(String[] args) {

        Instance instance1=Instance.getInstance();
        Instance instance2=Instance.getInstance();
        System.out.println(instance1==instance2);//true 这两个对象是同一个对象实例

        InstanceLazy single3=InstanceLazy.getInstance();
        InstanceLazy single4=InstanceLazy.getInstance();
        System.out.println(single3==single4);//true single1和single2是同一个对象
    }
}


http://www.kler.cn/a/456215.html

相关文章:

  • “宠物服务的跨平台整合”:多设备宠物服务平台的实现
  • 深入解析Spring Boot中的@ConfigurationProperties注解
  • SCSA:探索空间与通道注意力之间的协同效应
  • PS等软件学习笔记
  • SpringBoot配置文件、热部署、YAML语法、配置文件值注入
  • Java中处理if-else的几种高级方法
  • 深度学习:从原理到搭建基础模型
  • RabbitMQ HAProxy 负载均衡
  • 应对TensorFlow导入Keras时发生的错误问题
  • SPI实验 LED数码管
  • 用三种安全思维重新审视零信任网络
  • 云效流水线自动化部署web静态网站
  • opencl 封装简单api
  • CSDN编辑器
  • 长沙景区数据分析项目实现
  • Django实现异步视图adrf请求
  • Android Studio使用BottomNavigationView实现底部导航栏demo
  • 【Ext.js 初步入门】Ext.js 作用以及用法 概述
  • 企业内训|AI大模型在汽车行业的前沿应用研修-某汽车集团
  • Java MySQL 连接
  • 自动化测试- 自动化测试模型
  • RabbitMQ - 1 ( 7000 字 RabbitMQ 入门级教程 )
  • PyTorch框架实现的简单手写数字识别模型,使用MNIST数据集进行训练和测试
  • 32单片机从入门到精通之硬件架构——总线系统(二)
  • word中文献引用[]符号的上下标格式修改
  • 【反转链表系列】力扣206,92,25