多线程案例--单例模式

目录

一.什么是单例模式

二.饿汉模式

三.懒汉模式

3.1.单线程版

3.2.多线程版


一.什么是单例模式

单例模式是校招中最常考的设计模式之一

什么是设计模式:软件开发过程中会遇到很多常见的问题场景。针对这些问题场景,大佬们总结了一套固定的套路,按照这个套路实现代码,不会吃亏。

单例模式能保证某个类在程序中只存在唯一一份实例,而不会创建出多个实例。

单例模式具体的实现方式有很多.最常见的是"饿汉"和"懒汉"两种。

二.饿汉模式

类加载的同时就创建实例,并且将构造方法私有化(尽量早创建)

java 复制代码
class Singleton{
    private static Singleton instance=new Singleton();//类加载初始化,JVM保证线程安全
    public static Singleton getInstance(){
        return instance;
    }
    private Singleton(){

    }
}

静态成员初始化是在类加载的初始化阶段 触发的;类加载不是程序一启动就触发 ,而是第一次使用该类时 才触发;return 只是读操作,不涉及修改;静态变量只会创建并初始化一次 ;静态变量 / 静态代码块的初始化由 JVM 保证线程安全 ,JVM 在类初始化时会自动加锁 ,确保多线程下只会执行一次,不会产生线程安全问题

三.懒汉模式

3.1.单线程版

类加载的时候不创建实例.第一次使用的时候才创建实例(尽量晚创建)

java 复制代码
class Singleton {
    private static Singleton instance = null;
    private Singleton() {}
    public static Singleton getInstance() {
        if (instance == null) {
           instance = new Singleton();
        }
       return instance;
     }
 }

如果是单线程的话,完全是可以实现单例模式的,但是多线程就不行了,会产生线程安全问题

3.2.多线程版

这里需要进行加锁操作,以防线程调度

导致这种现象产生(不再是只实例化一个对象)

java 复制代码
class SingletonLazy{
    private static  SingletonLazy instance=null;
    private static Object loker=new Object();
    public static SingletonLazy getInstance(){
            synchronized (loker) {
                if (instance == null) {
                    instance = new SingletonLazy();
                }
                System.out.println(Thread.currentThread().getName()+"解锁");
            }
        return instance;
    }
    private SingletonLazy(){

    }
}

虽然这个代码已经线程安全了,但是还是有问题,我们可以看到,这个加锁操作并不是按需求加锁,如果实例创建了,就不涉及到线程安全的问题了,按理说就不需要加锁了,过度的加锁会导致后续线程阻塞等待,降低效率,所以我们可以在加锁之前做一个判断

java 复制代码
class SingletonLazy{
    private static SingletonLazy instance=null;
    private static Object loker=new Object();
    public static SingletonLazy getInstance(){
        if(instance==null) {
            System.out.println(Thread.currentThread().getName()+"判断instance是null的,加锁操作,避免过度枷锁");
            synchronized (loker) {
                System.out.println(Thread.currentThread().getName()+"被加锁");
                if (instance == null) {
                    System.out.println(Thread.currentThread().getName()+"判断instance是null的,创建新对象");
                    instance = new SingletonLazy();
                }
                System.out.println(Thread.currentThread().getName()+"解锁");
            }
        }
        return instance;
    }
    private SingletonLazy(){

    }
}

第一个if判断是为了避免过度加锁,第二个if是为了判断是否已经实例化对象。

但是这就完了吗?nonono,当然没有,我们上一张讲到的JVM 为了提高效率,会自作主张将长期未变,并且用的次数很多的数据存储在寄存器中直接拿取,其实JVM 为了优化效率还会进行指令重排的操作。

创建实例的步骤:1.创建内存。2.构造对象,初始化。3.把内存地址赋值给引用。如果不加上限制的话可能会导致指令重排,可能顺序为1,3,2.就会导致得到的是一个半初始化的对象,得到的是一个空格子,没有具体内容。

java 复制代码
class SingletonLazy{
    private static volatile SingletonLazy instance=null;
    private static Object loker=new Object();
    public static SingletonLazy getInstance(){
        if(instance==null) {
            System.out.println(Thread.currentThread().getName()+"判断instance是null的,加锁操作,避免过度枷锁");
            synchronized (loker) {
                System.out.println(Thread.currentThread().getName()+"被加锁");
                if (instance == null) {
                    System.out.println(Thread.currentThread().getName()+"判断instance是null的,创建新对象");
                    instance = new SingletonLazy();
                }
                System.out.println(Thread.currentThread().getName()+"解锁");
            }
        }
        return instance;
    }
    private SingletonLazy(){

    }
}

public class Demo1{
    public static void main(String[] args) {
        Thread t1=new Thread(()->{
            SingletonLazy.getInstance();
        });
        Thread t2=new Thread(()->{
            SingletonLazy.getInstance();
        });
        t1.start();
        t2.start();
    }
}
相关推荐
要开心吖ZSH1 天前
枚举单例模式详解-为什么需要枚举单例?
单例模式
凤头百灵鸟1 天前
Python语法进阶篇 --- 单例模式、魔法方法
javascript·python·单例模式
原来是猿2 天前
线程安全的单例模式
linux·服务器·开发语言·单例模式·策略模式
XiYang-DING4 天前
【Java EE】单例模式
java·单例模式·java-ee
XiYang-DING5 天前
【Java EE】volatile关键字
java·单例模式·java-ee
-凌凌漆-5 天前
【QML】qml和C++中同时使用单例模式
java·c++·单例模式
不知名的老吴5 天前
一文读懂:单例模式的经典案例分析
java·开发语言·单例模式
geovindu6 天前
go: Singleton Pattern
单例模式·设计模式·golang
╰つ栺尖篴夢ゞ7 天前
HarmonyOS Next面试题之主线程与子线程访问同一个单例,获取的对象是同一个吗?
单例模式·多线程·harmonyos·sendable·actor模型·内存隔离