• 设计模式系列-单例模式


    设计模式系列 - 单例模式

    image.png

    是什么?

    定义: 确保一个类只有一个实例,并且提供访问该实例的静态方法。

    单例的特点:

    • 在JVM中有且只能有一个实例存在。
    • 构造器必须私有(private修饰),禁止外部类通过构造器创建。
    • 提供一个全局公开的 getInstance() 方法获取该实例。

    饿汉式 - 线程安全

    饿汉式,简单理解就是比较饿,事先就迫不及待创建好实例, 然后调用 get 方法的时候,直接返回该实例即可。

    直接创建:

    carbon 1.png

    静态代码块创建:

    carbon 3.png

    因为是事先创建好实例,所以没有线程安全问题。

    懒汉式 - 线程不安全

    懒汉式,可以理解为它懒,只有到真正要用到实例的时候,它才会去创建。

    简单实现 ~~

    carbon 4.png

    这种写法会有会有线程问题, 如果多个线程都执行到 if(lhSingleton == null) 并且通过,那么就会创建多个实例。

    要解决这个问题也简单,给 getInstance() 方法加锁就行了,保证同一时刻只有一个线程获取实例。即可。说干就干 ~~

    carbon 6.png

    这样是比较干脆的解决了线程安全问题。

    这样做有个缺点,就是已经有实例了,每次调用还是要加锁排队,极大的影响性能。不推荐这样写。

    我们要做到,只有最开始需要创建实例的时候,才加锁同步。那继续优化吧 ~~ 也就是双检锁了!

    双检锁 - 线程安全

    carbon 7.png

    • 先检查实例是否已存在,不存在才加锁
    • 考虑到有多个线程会通过第一次的判断, 即使加了锁,这些线程依旧会排队执行同步代码块中的创建实例逻辑,还是可能会创建多次的,所以需要在同步代码块种进行二次判断。

    sjsSingleton 采用 volatile 关键字修饰也是很有必要的, sjsSingleton = new SJSSingleton();这段代码其实分为三步执行:

    1. 为 sjsSingleton 实例在堆中分配内存空间
    2. 初始化 sysSingleton
    3. 将 jssSingleton 指向分配的内存地址

    但是由于 JVM 具有指令重排序的特性,执行顺序可能变成1>3>2。指令重排在单线程环境下不会出现问题,但是在多线程环境下,会导致一个线程获得还没有初始化的实例。

    使用 volatile 可以禁止 JVM 指令重排, 保证在多线程环境下也能正常运行。

    volatile 除了禁止JVM 指令重排之外,还可以保证变量内存可见性,想具体了解,可以去查看相关资料!

    本文由博客一文多发平台 OpenWrite 发布!

  • 相关阅读:
    aircrack-ng 多网卡启动后环境清理
    Docker create image
    预加载(学习一)
    activity+fragment多次切换出现页面空白问题
    万能的Volley
    关于下拉刷新你是否真的非常理解还是只会搬砖?附 Android 实例子源代码文件下载地址380个合集
    如何将Java源代码文件的编码从GBK转为UTF-8?
    如何操作笔记本显得逼格很高?
    跑马灯源代码
    关于java、Android中Math的一些用法
  • 原文地址:https://www.cnblogs.com/liuyingke/p/15481809.html
Copyright © 2020-2023  润新知