多线程案例--单例模式

目录

一.什么是单例模式

二.饿汉模式

三.懒汉模式

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();
    }
}
相关推荐
basketball61614 小时前
C++ 单例模式完全指南:从饿汉式到现代 C++ 的最佳实践
java·c++·单例模式
W.W.H.1 天前
Qt 应用防多开:极简单例方案
开发语言·qt·单例模式·共享内存
++==1 天前
设计模式:单例模式和观察者模式实现方式以及优化
观察者模式·单例模式·设计模式
摇滚侠4 天前
Java 饿汉式 单例模式
java·开发语言·单例模式
游乐码5 天前
Unity坦克案例疑难记录(一)
unity·单例模式
想学会c++8 天前
单例模式笔记总结
c++·笔记·单例模式
是个西兰花8 天前
单列模式和C++中的类型转换
c++·单例模式·设计模式·rtti
nnsix8 天前
设计模式 - 单例模式 笔记
笔记·单例模式·设计模式
cui_ruicheng8 天前
Linux线程(四):线程池、日志系统与单例模式
linux·开发语言·单例模式
2301_815279529 天前
实战分享实现 C++ 管理类单例模式:特点与最佳实践
javascript·c++·单例模式