单例模式的八种写法、单例和并发的关系

文章目录

  • 1.单例模式的作用
  • 2.单例模式的适用场景
  • 3.饿汉式
    • 静态常量(可用)
    • 静态代码块(可用)
  • 4.懒汉式
    • 线程不安全(不可用)
    • 同步方法(线程安全,但不推荐用)
    • 同步代码块(线程不安全,不可用)
    • 双重检查 + volatile(推荐用)
    • 静态内部类(推荐用)
    • 枚举(推荐用)

1.单例模式的作用

为什么需要单例?

  • 节省内存和计算
  • 保证结果正确
  • 方便管理

2.单例模式的适用场景

  1. 无状态的工具类:比如日志工具类,不管是在哪里使用,我们需要的只是它帮我们记录日志信息,除此之外,并不需要在它的实例对象上存储任何状态,这时候我们就只需要一个实例对象即可。
  2. 全局信息类:比如我们在一个类上记录网站的访问次数,我们不希望有的访问被记录在对象 A 上,有的却记录在对象 B 上,这时候我们就让这个类成为单例。

3.饿汉式

静态常量(可用)

/**
 * 饿汉式(静态常量)(可用)
 */
public class Singleton1 {

    // 由于加了static关键字,根据JVM的规定,在类加载的时候就会完成INSTANCE的实例化,这样就避免了线程同步问题
    private final static Singleton1 INSTANCE = new Singleton1();

    // 构造函数是私有的
    private Singleton1() {

    }

    public static Singleton1 getInstance() {
        return INSTANCE;
    }
}

静态代码块(可用)

/**
 * 饿汉式(静态代码块)(可用)
 */
public class Singleton2 {

    private final static Singleton2 INSTANCE;

    // 与上一种写法类似,由JVM保证了线程安全
    static {
        INSTANCE = new Singleton2();
    }

    // 构造函数是私有的
    private Singleton2() {

    }

    public static Singleton2 getInstance() {
        return INSTANCE;
    }
}

4.懒汉式

线程不安全(不可用)

/**
 * 懒汉式(线程不安全)(不可用)
 */
public class Singleton3 {

    private static Singleton3 instance;

    // 构造函数是私有的
    private Singleton3() {

    }

    public static Singleton3 getInstance() {
        // 这种写法是线程不安全的,不可用
        if (instance == null) {
            instance = new Singleton3();
        }
        return instance;
    }
}

同步方法(线程安全,但不推荐用)

/**
 * 懒汉式(线程安全)(不推荐用)
 */
public class Singleton4 {

    private static Singleton4 instance;

    // 构造函数是私有的
    private Singleton4() {

    }

    // 这种写法虽然是线程安全的,但是效率太低,不推荐用
    public synchronized static Singleton4 getInstance() {
        if (instance == null) {
            instance = new Singleton4();
        }
        return instance;
    }
}

同步代码块(线程不安全,不可用)

/**
 * 懒汉式(线程不安全)(不可用)
 */
public class Singleton5 {

    private static Singleton5 instance;

    // 构造函数是私有的
    private Singleton5() {

    }

    public static Singleton5 getInstance() {
        // 这种写法并不是线程安全的,不可用
        if (instance == null) {
            synchronized (Singleton5.class) {
                instance = new Singleton5();
            }
        }
        return instance;
    }
}

双重检查 + volatile(推荐用)

优点:线程安全,延迟加载,效率较高。

/**
 * 双重检查 + volatile(推荐用)
 */
public class Singleton6 {

    // volatile防止重排序
    private volatile static Singleton6 instance;

    // 构造函数是私有的
    private Singleton6() {

    }

    public static Singleton6 getInstance() {
        // 双重检查保证线程安全
        if (instance == null) {
            synchronized (Singleton6.class) {
                if (instance == null) {
                    instance = new Singleton6();
                }
            }
        }
        return instance;
    }
}

为什么要用 volatile?

新建对象 rs = new Resource() 实际上有 3 个步骤:

  • construct empty resource()
  • call constructor
  • assign to rs

如下图所示,重排序会带来NPE问题(NullPointerException, 空指针异常),而使用 volatile 可以防止重排序。

在这里插入图片描述

静态内部类(推荐用)

/**
 * 静态内部类(线程安全,懒加载)(推荐用)
 */
public class Singleton7 {

    // 构造函数是私有的
    private Singleton7() {

    }

    // 由JVM的规定可知,这种写法同时满足了线程安全和懒加载两个优点
    private static class SingletonInstance {
        private static final Singleton7 INSTANCE = new Singleton7();
    }

    public static Singleton7 getInstance() {
        return SingletonInstance.INSTANCE;
    }
}

枚举(推荐用)

单例模式的书写:

/**
 * 枚举(线程安全,懒加载)(推荐用)
 */
public enum Singleton8 {
    INSTANCE;

    public void whatever() {

    }
}

单例的使用:

Singleton8.INSTANCE.whatever();

哪种单例的实现方案最好?

Joshua Bloch 大神在《Effective Java》中明确表达过的观点:使用枚举实现单例的方法虽然还没有广泛采用,但是单元素的枚举类型已经成为实现 Singleton 的最佳方法。

  • 写法简单
  • 线程安全有保障
  • 懒加载
  • 避免反序列化破坏单例

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/319980.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【我想开发一个小程序,大概需要多少钱?】

小程序开发为什么报价差距很大?主要是因为小程序的实现方法和功能模型不同。 小程序的实现方法: 实现方法主要分为SAAS小程序、定制小程序和第三方平台小程序。不同的实现方法价格都是不一样的,大概的区间如下: SAAS小程序和第三…

Github 2024-01-14 Go开源项目日报 Top10

根据Github Trendings的统计,今日(2024-01-14统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量Go项目10TypeScript项目1 frp: 一个开源的快速反向代理 创建周期:2946 天开发语言:G…

第 2 章 数据结构和算法概述

文章目录 2.1 数据结构和算法的关系2.2 看几个实际编程中遇到的问题2.2.1 问题一-字符串替换问题2.2.2 一个五子棋程序2.2.3 约瑟夫(Josephu)问题(丢手帕问题)2.2.4 其它常见算法问题: 2.3 线性结构和非线性结构2.3.1 线性结构2.3.2 非线性结构 2.1 数据结构和算法的关系 数据 …

扫雷游戏棋盘的打印,判断输赢,深度分析

少年们,大家好,我是博主那一脸阳光,我来分享扫雷的打印和判断输赢,代码如何编写,如何使用,深度理解扫雷的游戏。 数据结构的分析和理论 我上次介绍棋盘的初始化,但是如果不打印出来&#xff0…

AI 大模型面试指南(含答案)大放送!

▼最近直播超级多,预约保你有收获 今晚直播:《大模型构建企业知识库实践》 AI 大模型技术经过2023年的狂飙,2024年必将迎来应用的落地,对 IT 同学来讲,这里蕴含着大量的技术机会,越来越多的企业开始招聘 AI…

2624. 蜗牛排序

说在前面 🎈不知道大家对于算法的学习是一个怎样的心态呢?为了面试还是因为兴趣?不管是出于什么原因,算法学习需要持续保持。 题目描述 请你编写一段代码为所有数组实现 snail(rowsCount,colsCount) 方法,…

数据库备份脚本嘎嘎香,被秀到了!

📢📢📢📣📣📣 哈喽!大家好,我是【IT邦德】,江湖人称jeames007,10余年DBA及大数据工作经验 一位上进心十足的【大数据领域博主】!😜&am…

mybatisplus(service CRUD 接口)

一、我们在控制器层都是调用Service层&#xff0c;不会直接调用仓储层。现在我给大家介绍一下怎么快速实现Service 的CRUD 定义接口&#xff1a;IProductService 继承IService<实体> package com.saas.plusdemo;import com.baomidou.mybatisplus.extension.service.ISe…

Sentinel限流、熔断

1、限流 单个服务节点限流 sentinel 提供了两种不同的隔离机制&#xff1a;信号量隔离和线程池隔离&#xff0c;它们的主要区别如下&#xff1a; 信号量隔离&#xff08;Semaphore Isolation&#xff09;&#xff1a; 原理&#xff1a;信号量隔离基于计数器&#xff08;或称令…

iOS swift UISlider改变进度条的高度和圆形滑块的大小

文章目录 1.改变进度条的高度&#xff08;亲测有效&#xff09;2.改变圆形滑块的大小&#xff08;亲测有效&#xff09; 1.改变进度条的高度&#xff08;亲测有效&#xff09; import UIKitclass CustomSlider: UISlider {// 设置轨道高度var trackHeight: CGFloat 10// 重写…

Python数据结构——字符串

目录 一、字符串的不变性 二、字符串的常见方法介绍 三、字符串对象的join()和split()方法 一、字符串的不变性 1、属于不可变对象&#xff0c;不能通过索引操作来改变字符串对象本身 s I like Python s[7] p 要修改字符串&#xff0c;需要使用字符串的replace()方法&am…

信息系统安全——Linux 访问控制机制分析

实验 4 Linux 访问控制机制分析 4.1 实验名称 《Linux 访问控制机制分析》 4.2 实验目的 1 、熟悉 Linux基本访问控制机制使用和原理 2 、熟悉 Linux S 位的作用和使用 3 、熟悉强制访问控制 Selinux 原理及其使用 4.3 实验步骤及内容 1 、Linux 基本访问控制机制 &#xff08…

2024.1.13力扣每日一题——构造限制重复的字符串

2024.1.13 题目来源我的题解方法一 计数模拟 题目来源 力扣每日一题&#xff1b;题序&#xff1a;2182 我的题解 方法一 计数模拟 因为字符串s由小写字母构成&#xff0c;因此使用一个int[26]的数组保存每个字符的数量&#xff0c;然后从最大的字符开始构造结果字符串sb&…

PLAN B KRYPTO ASSETS GMBH CO. KG 普兰资产管理公司

引领加密技术不断演进 PLAN B KRYPTO ASSETS普兰资产管理以其独创的「Trident Strategy三叉戟模型」技术为基础&#xff0c;持续推动加密技术的发展&#xff0c;打造 Schutz&#xff08;舒茨盾&#xff09; AI 金融隐私匿名公链。致力于提供高效的技术服务&#xff0c;基于机构…

[Vulnhub靶机] DC-1

[Vulnhub靶机] DC-1靶机渗透思路及方法&#xff08;个人分享&#xff09; 靶机下载地址&#xff1a; https://download.vulnhub.com/dc/DC-1.zip 靶机地址&#xff1a;192.168.67.28 攻击机地址&#xff1a;192.168.67.3 一、信息收集 1.使用 arp-scan 命令扫描网段内存活的…

Multimodal Prototypical Networks for Few-shot Learning

tcGAN is provided with an embedding ϕ T \phi_T ϕT​() of the textual description 辅助信息 作者未提供代码

【论文阅读】Consistency Models

文章目录 IntroductionDiffusion ModelsConsistency ModelsDefinitionParameterizationSampling Training Consistency Models via DistillationTraining Consistency Models in IsolationExperiment Introduction 相比于单步生成的模型&#xff08;例如 GANs, VAEs, normalizi…

怎样制作一本旅游电子相册呢?

​随着数码技术的发展&#xff0c;旅游电子相册已成为越来越多旅游爱好者的必备工具。它不仅能让您随时随地欣赏自己的旅行回忆&#xff0c;还能分享给亲朋好友&#xff0c;甚至上传到社交媒体上&#xff0c;让更多人了解您的旅行故事。那么&#xff0c;如何制作一本精美的旅游…

最新国内可用GPT4、Midjourney绘画、DALL-E3文生图模型教程

一、前言 ChatGPT3.5、GPT4.0、GPT语音对话、Midjourney绘画&#xff0c;文档对话总结DALL-E3文生图&#xff0c;相信对大家应该不感到陌生吧&#xff1f;简单来说&#xff0c;GPT-4技术比之前的GPT-3.5相对来说更加智能&#xff0c;会根据用户的要求生成多种内容甚至也可以和…

Redis的主从配置,哨兵模式,集群模式

目录 什么是主从复制&#xff1f; 主从复制的作用&#xff1f; 主从复制的流程&#xff1f; 搭建Redis的主从复制 安装Redis 环境准备 修改内核参数 安装Redis 定义systemd服务管理脚本 修改Redis配置文件&#xff08;Master节点操作&#xff09;192.168.17.25 修改Re…
最新文章