多线程代码案例--单例模式

简介: 多线程代码案例--单例模式

                  目录

                               🚀1.什么是单例模式

                           🚀 2.饿汉模式

    🚀3.懒汉模式--多线程(不安全版本)

                   🚀4.懒汉模式--多线程(安全版本)

              🚀5 总结


1.什么是单例模式


单例模式其实是一种设计模式,在平常工作中很常用,是一种固定的模板,就像下棋的棋谱一样,这个很重要,需要我们重点掌握


单例模式分为饿汉模式和懒汉模式,饿汉模式是急迫型的,而懒汉模式是从容型的

举个很简单的例子,从硬盘读取内容到显示器上,有两种方式,一种是要等一会,把所有的数据全都读到显示器上,还有一种是立即显示,一点一点读,前者是饿汉模式,后者就是懒汉模式,两者相比,当然是懒汉模式更高效了


2.饿汉模式


下面我们就来实现一下单例模式的第一个:饿汉模式

class Singleton{
    //创建唯一一个实例
    private static Singleton  instance=new Singleton();
    //获取唯一实例
    public static Singleton getInstance(){
        return instance;
    }
        //构造方法私有化,保证不能再new实例
    private Singleton(){
    }
}
public class ThreadingDemo1 {
    public static void main(String[] args) {
            Singleton s1=Singleton.getInstance();
            Singleton s2=Singleton.getInstance();
    }
}


这样写s1和s2获取到的都是唯一的实例

当再次想new的时候,就会报错

所谓单例模式,就是保证只能有一个实例


3.懒汉模式(不安全版本)


懒汉模式就是能不new就不new,需要我new我再new

下面来实现一下懒汉模式

class SingletonLazy{
    private static SingletonLazy instance=null;
    public static SingletonLazy getInstance(){
        if(instance==null){
            instance=new SingletonLazy();
        }
        return instance;
    }
    private  SingletonLazy(){
    }
}
public class ThreadDemo2 {
    public static void main(String[] args) {
            SingletonLazy s1=SingletonLazy.getInstance();
            SingletonLazy s2=SingletonLazy.getInstance();
        System.out.println(s1==s2);
    }
}


懒汉就是我先不创建对象,需要的时候我再干活


下面我们来分析一下这两个代码


7e1b18644b964196bdd104f168d282e0.png


饿汉模式中,没有涉及到修改操作,就是一个简单的返回 ,一个简答的读操作.所以是线程安全的


懒汉模式中,如果是单个线程调用,那一定就是线程安全的,但是在多线程中,如果多个线程调用new操作,那么就不安全了,类似于count++操作,不是原子的了,下面来画个图


48d09eb4712743b7800b6caf3bbdf8e6.png

这个情况就会new多个对象,那么 就会产生线程不安全的问题

其实也就是因为操作不是原子引起的,if 判断和new操作不是原子的,所以我们采用加锁的方式

如下面的代码


public static SingletonLazy getInstance() {
    synchronized (SingletonLazy.class) {
        if (instance == null) {
            instance = new SingletonLazy();
        }
        return instance;
    }
}


其实只有在第一次new对象的时候会产生这样的问题,所以如果每一次都加锁就很耗费资源,降低效率,所以我们再加锁前,判断一下要不要加锁,如果对象还没有创建,那就加锁,如果已经有了,就不用再加锁了,那么就使用双重if判定


注意!!!


这里的两个if条件一模一样,但是意义天差地别,第一个if是判断要不要加锁,第二个if是为了判断要不要new一个对象,创建一个实例

如下代码


public static SingletonLazy getInstance() {
    if (instance == null) {
        synchronized (SingletonLazy.class) {
            if (instance == null) {
                instance = new SingletonLazy();
            }
        }
    }
        return instance;
}


然后针对new操作,可能会产生指令重排序的问题,之前我们就讨论过这个问题,这里就不再赘述,那么我们为了防止这个问题的产上,使用volatile关键字


4.懒汉模式(安全版本)


最终代码


class SingletonLazy {
      volatile private static SingletonLazy instance = null;
    public static SingletonLazy getInstance() {
        if (instance == null) {
            synchronized (SingletonLazy.class) {
                if (instance == null) {
                    instance = new SingletonLazy();
                }
            }
        }
            return instance;
    }
    private  SingletonLazy(){
    }
}
public class ThreadDemo2 {
    public static void main(String[] args) {
            SingletonLazy s1=SingletonLazy.getInstance();
            SingletonLazy s2=SingletonLazy.getInstance();
        System.out.println(s1==s2);
    }
}


         5.总结:

                                              保证懒汉模式线程安全办法:

           1.加锁,保证if和new是原子的

          2.双重if判定,防止不必要的加锁

   3.加volatile关键字,禁止指令重排序,保证后面的线程拿到的是完整的对象

     饿汉模式:是天然线程安全的,涉及到读操作

    懒汉模式:不安全,需要操作把它边安全


以上就是这期要分享的内容,我们下期再见了,886!!!

             

目录
打赏
0
0
0
0
0
分享
相关文章
JAVA线程池有哪些队列? 以及它们的适用场景案例
不同的线程池队列有着各自的特点和适用场景,在实际使用线程池时,需要根据具体的业务需求、系统资源状况以及对任务执行顺序、响应时间等方面的要求,合理选择相应的队列来构建线程池,以实现高效的任务处理。
157 12
深入理解Java中synchronized三种使用方式:助您写出线程安全的代码
`synchronized` 是 Java 中的关键字,用于实现线程同步,确保多个线程互斥访问共享资源。它通过内置的监视器锁机制,防止多个线程同时执行被 `synchronized` 修饰的方法或代码块。`synchronized` 可以修饰非静态方法、静态方法和代码块,分别锁定实例对象、类对象或指定的对象。其底层原理基于 JVM 的指令和对象的监视器,JDK 1.6 后引入了偏向锁、轻量级锁等优化措施,提高了性能。
120 3
PHP 互斥锁:如何确保代码的线程安全?
在多线程和高并发环境中,确保代码段互斥执行至关重要。本文介绍了 PHP 互斥锁库 `wise-locksmith`,它提供多种锁机制(如文件锁、分布式锁等),有效解决线程安全问题,特别适用于电商平台库存管理等场景。通过 Composer 安装后,开发者可以利用该库确保在高并发下数据的一致性和安全性。
77 6
【JavaEE】——单例模式引起的多线程安全问题:“饿汉/懒汉”模式,及解决思路和方法(面试高频)
单例模式下,“饿汉模式”,“懒汉模式”,单例模式下引起的线程安全问题,解锁思路和解决方法
|
6月前
|
Java多线程通信新解:本文通过生产者-消费者模型案例,深入解析wait()、notify()、notifyAll()方法的实用技巧
【10月更文挑战第20天】Java多线程通信新解:本文通过生产者-消费者模型案例,深入解析wait()、notify()、notifyAll()方法的实用技巧,包括避免在循环外调用wait()、优先使用notifyAll()、确保线程安全及处理InterruptedException等,帮助读者更好地掌握这些方法的应用。
60 1
单例模式下引发的线程安全问题
单例模式确保类在进程中仅有一个实例,适用于如数据库连接等场景。分为饿汉式与懒汉式:饿汉式在类加载时创建实例,简单但可能浪费资源;懒汉式延迟创建实例,需注意线程安全问题,常采用双重检查锁定(Double-Checked Locking)模式,并使用 `volatile` 关键字避免指令重排序导致的问题。
112 2
单例模式下引发的线程安全问题
【多线程-从零开始-柒】单例模式,饿汉和懒汉模式
【多线程-从零开始-柒】单例模式,饿汉和懒汉模式
86 0
python3多线程实战(python3经典编程案例)
该文章提供了Python3中多线程的应用实例,展示了如何利用Python的threading模块来创建和管理线程,以实现并发执行任务。
170 0
WPF开发者必读:资源字典应用秘籍,轻松实现样式与模板共享,让你的WPF应用更上一层楼!
【8月更文挑战第31天】在WPF开发中,资源字典是一种强大的工具,用于共享样式、模板、图像等资源,提高了应用的可维护性和可扩展性。本文介绍了资源字典的基础知识、创建方法及最佳实践,并通过示例展示了如何在项目中有效利用资源字典,实现资源的重用和动态绑定。
218 0
|
2月前
|
Linux编程: 在业务线程中注册和处理Linux信号
本文详细介绍了如何在Linux中通过在业务线程中注册和处理信号。我们讨论了信号的基本概念,并通过完整的代码示例展示了在业务线程中注册和处理信号的方法。通过正确地使用信号处理机制,可以提高程序的健壮性和响应能力。希望本文能帮助您更好地理解和应用Linux信号处理,提高开发效率和代码质量。
58 17
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等