JAVA多线程中的单例模式

一.什么是单例模式?

在 Java 里,单例模式指的是一个类仅有一个实例,并且提供一个全局访问点**(公有get方法)来获取该实例**。在多线程环境下实现单例模式时,需要保证线程安全,避免多个线程同时创建多个实例。下面介绍几种常见的多线程单例模式实现方式

二.饿汉式

在类加载时就创建了实例

1.代码示例

java 复制代码
class Singleton {
    //在类加载时直接创建实例
    //static 修饰引用变量,意味着这个变量属于类,而不是实例
    //确保类只有一个实例。这里用 static 让 instance 属于类,只有一份。
    private static Singleton instance = new Singleton();
    //提供公有的get方法来让外部获取唯一实例
    public static Singleton getInstance() {
        return instance;
    }

    // 把构造方法设为 private。此时在类的外面,就无法继续 new 实例了.
    private Singleton() {
    }
}
 class Demo20 {
    public static void main(String[] args) {
        // 如果代码这么写,就违背初衷,就应该禁止这个类在类外部被 new.
        // Singleton instance2 = new Singleton();
        Singleton instance = Singleton.getInstance();
    }
}

2.以上代码是线程安全的------为什么?

java 复制代码
public static Singleton getInstance() {
        return instance;
    }

因为上述代码中这段操作只涉及到"读取数据",不涉及到修改

三.懒汉式

不是在类加载时就创建了实例

先来看一段代码

1.代码示例

java 复制代码
class SingletonLazy {
    private static SingletonLazy instance = null;

    public static SingletonLazy getInstance() {
        if (instance == null) {
            instance = new SingletonLazy();
        }
        return instance;
    }
    // 把构造方法设为 private。此时在类外部,就无法继续 new 实例了.
    private SingletonLazy() {}
}

 class Demo2 {
    public static void main(String[] args) {
        SingletonLazy instance = SingletonLazy.getInstance();
        SingletonLazy instance2 = SingletonLazy.getInstance();
    }
}

2.解释

这种方式在首次调用getInstance( )的时候才会创建实例,后续再调用getInstance( ),则直接返回实例(不new)。

3.但在多线程环境下不安全--为什么?

java 复制代码
 if (instance == null) {
            instance = new SingletonLazy();
        }
        return instance;

在上述代码中这段操作既涉及到了读取,也涉及到了修改(将SingletonLazy对象赋值给引用变量instance)

假设有两个线程 t1,t2进行下方操作

java 复制代码
SingletonLazy instance = SingletonLazy.getInstance();

导致实例被创建出多份

4.如何修改?

加锁

4.1 synchronized修饰此段代码块

java 复制代码
class SingletonLazy {
    private static SingletonLazy instance = null;

    public static SingletonLazy getInstance() {
        //这里
        synchronized (Singleton.class){
             if(instance == null) {
                instance = new SingletonLazy();
            }
        }
        return instance;
    }
   
    private SingletonLazy() {}
}

4.2 synchronized修饰getInstance( )方法

java 复制代码
class SingletonLazy {
    private static SingletonLazy instance = null;
    //这里
    public static synchronized SingletonLazy getInstance() {
      
             if(instance == null) {
                instance = new SingletonLazy();
            }

        return instance;
    }

    private SingletonLazy() {}
}

5.有个小的新问题

线程不安全并不是一直都不安全。只是在多线程(多个线程)环境下,首轮调用getInstance( )方法才会不安全。一旦实例创建好,多个线程同时调用getInstance( )方法也并不会触发线程不安全问题。

总:会带来一定的性能开销

6.如何解决?

怎样既保持线程安全,也减少同步带来的性能开销

6.1 解决方法

双重检查锁定

java 复制代码
public static SingletonLazy getInstance() {
        //加上判定条件
        if (instance==null){
            //在此处加锁
            synchronized (Singleton.class){
                if(instance == null) {
                    instance = new SingletonLazy();
                }
            }
        }

        return instance;
}

 

6.2 新问题 (这里可以不看)

6.2.1 解决方法(这里看)

使用 volatile 关键字保证可见性

java 复制代码
 private static volatile SingletonLazy instance = null;
相关推荐
fb_1234524 分钟前
Linux磁盘分区从入门到实操:MBR_GPT全解析+分区工具实战指南
java·linux·gpt
码智社1 小时前
JSON 零基础到资深全体系教程
java·json
峥嵘life2 小时前
Android WiFi 热点 Channel 信道 和 Frequency 频率 转换总结
android·开发语言
wgego2 小时前
基础的反序列化一些总结(php和java)
java·开发语言·笔记
冻柠檬飞冰走茶3 小时前
PTA基础编程题目集 7-8超速判断(C++语言实现)
开发语言·数据结构·c++·算法
机建狂魔3 小时前
Codex 接入第三方模型 API 实战:以 Mimo 为例
java·服务器·数据库·ai·ai编程·codex
山峰哥4 小时前
数据库工程与SQL调优:从慢查询到秒级响应的实战之路
java·开发语言·数据库·sql·深度优先·启发式算法
乐观的Terry4 小时前
11、发布系统-用户认证与权限体系
java·spring boot·spring·spring cloud·mybatis
前端开发张小七4 小时前
Java 学习笔记 · 第二课:面向对象核心(封装、继承、多态)及接口与异常
java·后端·程序员
wangjialelele4 小时前
Selenium4 + Java Web自动化测试入门指南:从环境搭建到常用操作详解
java·开发语言·前端·测试工具·自动化