zoukankan      html  css  js  c++  java
  • 设计模式系列-单例模式

    设计模式系列 - 单例模式

    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 发布!

  • 相关阅读:
    C++面向对象三大特性
    4G通信技术LTE介绍
    汉澳战斗檄文,跟着汉澳去战斗
    AdapterView及其子类之二:使用ListActivity及ArrayAdapter创建列表
    [置顶] Objective-C ,ios,iphone开发基础:protocol 协议(委托,代理)的声明
    C语言中几种类型所占字节数
    UART, SPI, IIC的详解及三者的区别和联系
    数学基础详解 2——概率论与数理统计
    1—机器学习简介
    Python基础(11)——反射、异常处理
  • 原文地址:https://www.cnblogs.com/liuyingke/p/15481809.html
Copyright © 2011-2022 走看看