Java面试题(四) 单例模式是如何在并发多线程下稳如老狗的?

一. 单例模式

单例模式,属于创建类型的一种常用的软件设计模式。
通过单例模式的方法创建的类在当前进程中只有一个实例
根据需要,也有可能一个线程中属于单例,如:仅线程上下文内使用同一个实例 (来源:百度百科)	

简单总结:单例模式就是需要一个私有构造器,一个私有静态类对象

二. 单例模式在单线程下

	//懒汉式
    private static SingletonDemo instance = null;

    private SingletonDemo() {

        System.out.println(Thread.currentThread().getName() + "\t 我是构造方法 SingletonDemo");
    }

    public static SingletonDemo getInstance() {
        //判断
        if (instance == null) {
               instance = new SingletonDemo();
            }
        }
        return instance;
    }

调用单例模式:

public static void main(String[] args) {
        //单线程
        System.out.println(SingletonDemo.getInstance() == SingletonDemo.getInstance());
    }

运行结果:
在这里插入图片描述

三. 单例模式在多线程下

单例模式不变,添加多线程测试

测试代码:

public static void main(String[] args) {

        //单线程
        //System.out.println(SingletonDemo.getInstance() == SingletonDemo.getInstance());

        System.out.println("-------------华丽的分割线------------------");

        //并发多线程
        for (int i = 1; i <= 10; i++) {
            new Thread(() -> {
                SingletonDemo.getInstance();
            }, String.valueOf(i)).start();
        }
    }

运行结果:
在这里插入图片描述
出现了单例模式创建多个对象的情况

四. 解决单例模式在多线程下的问题

解决方式:
	1. 使用DCL(Double Check Lock)双端检锁机制
	2. 加Volatile关键字

代码加注释:

	//懒汉式
    /**
     * 为什么要加 Volatile关键字?
     *      因为 DCL机制还是有点安全隐患的,因为指令重排机制可能会导致其犯错,创建多个对象,
     *      所以为了万无一失把指令重排禁止掉。
     *
     * volatile 禁止指令重排
     */
    private static volatile SingletonDemo instance = null;

    private SingletonDemo() {
        System.out.println(Thread.currentThread().getName() + "\t 我是构造方法 SingletonDemo");
    }

    /**
     * 1. 加 synchronized到方法上解决多线程问题,方案不好,下手太重。
     * 2. 使用 DCL(Double Check Lock)双端检锁机制
     * DCL: 简单理解就是在加锁前后都检索判断一次
     */
    public static /*synchronized*/ SingletonDemo getInstance() {
        //判断
        if (instance == null) {
            //加锁
            synchronized (SingletonDemo.class) {
                //判断
                if (instance == null) {
                    instance = new SingletonDemo();
                }
            }
        }
        return instance;
    }

测试代码:

public static void main(String[] args) {

        //单线程
        //System.out.println(SingletonDemo.getInstance() == SingletonDemo.getInstance());

        System.out.println("-------------华丽的分割线------------------");

        //并发多线程
        for (int i = 1; i <= 10; i++) {
            new Thread(() -> {
                SingletonDemo.getInstance();
            }, String.valueOf(i)).start();
        }

    }

运行结果:
在这里插入图片描述

总结:单例模式在多线程下稳如老狗的关键,就是DCL机制和Volatile关键字。

猜你喜欢

转载自blog.csdn.net/w_x_A__l__l/article/details/106598453