专业编程基础技术教程

网站首页 > 基础教程 正文

一篇看懂各种单例模式实现的优缺点

ccvgpt 2024-07-28 12:12:08 基础教程 7 ℃
/**
 * 饿汉式
 * 优点:实现简单,类加载时就创建,线程安全
 * 缺点:类加载时创建,如果实例没有被使用,会造成内存浪费
 */
public class SingleInstance {
    private static final SingleInstance signalInstance = new SingleInstance();

    private SingleInstance() {
    }

    public static SingleInstance getInstance() {
        return signalInstance;
    }
}

/**
 * 懒汉式 1
 * 优点:在需要是创建实例,减少了对内存的浪费
 * 问题:多线程下,不同线程获取的实例不一定是同一个
 */
public class SingleInstance {
    private static SingleInstance signalInstance;

    private SingleInstance() {
    }

    public static SingleInstance getInstance() {
        if (signalInstance == null) {
            // 此处可能多个线程同时进入,线程1和线程2可能同时创建不同的实例,导致线程1和线程2获取的实例不同
            signalInstance = new SingleInstance();
        }
        return signalInstance;
    }
}

/**
 * 懒汉式 2
 * 优点:在需要是创建实例,减少了对内存的浪费,通过对方法加锁,解决了 懒汉式 1 中多线程遇到的问题
 * 缺点:由于对方法加了锁,导致性能下降
 */
public class SingleInstance {
    private static SingleInstance signalInstance;

    private SingleInstance() {
    }

    public static synchronized SingleInstance getInstance() {
	// 其它业务逻辑....
        if (signalInstance == null) {
            signalInstance = new SingleInstance();
        }
        return signalInstance;
    }
}

/**
 * 懒汉式 3
 * 优点:解决了部分懒汉式 2 中的性能问题
 * 缺点:由于每次判断实例是否已经被初始化都需要加锁,导致性能下降
 */
public class SingleInstance {
    private static SingleInstance signalInstance;

    private SingleInstance() {
    }

    public static SingleInstance getInstance() {
        // 其它业务逻辑。。。。
        synchronized (SingleInstance.class) {
            if (signalInstance == null) {
                signalInstance = new SingleInstance();
            }
        }
        return signalInstance;
    }
}

/**
 * 懒汉式 4
 * 优点:解决了 懒汉式3 中的性能问题
 * 问题:多线程获取实例的时候可能因为指令重排序导致线程获取实例内容不正确问题
 */
public class SingleInstance {
    private static SingleInstance signalInstance;

    private SingleInstance() {
    }

    public static SingleInstance getInstance() {
        // 其它业务代码。。。。
        if (signalInstance == null) { // 16行
            synchronized (SingleInstance.class) {
                if (signalInstance == null) {
                    // 多线程访问时,由于下面代码在创建实例的时候可能会存在指令重排序问题,导致 signalInstance 为空
                    /*
                    问题原因:
                    signalInstance = new SingleInstance() 执行的步骤是:
                        1.分配内存空间
                        2.赋默认值
                        3.将 signalInstance 指向分配的内存空间
                    由于指令重排序问题,步骤2和3可能会乱序,导致先执行步骤3,再执行步骤2,这个时候如果
                    有其他线程调用getInstance()方法,在执行16行判断的时候,signalInstance不为空,直接将实例返回了,
                    但返回的实例并不是正确赋值的实例
                     */
                    signalInstance = new SingleInstance();
                }
            }
        }
        return signalInstance;
    }
}

/**
 * 懒汉式 5
 * 优点:解决了懒汉式4中的指令重排序问题
 */
public class SingleInstance {
    /**
     * volatile 关键词可以禁止 signalInstance 在实例化过程中指令重排序
     */
    private volatile static SingleInstance signalInstance;

    private SingleInstance() {
    }

    public static SingleInstance getInstance() {
        // 其它业务代码。。。。
        if (signalInstance == null) {
            synchronized (SingleInstance.class) {
                if (signalInstance == null) {
                    signalInstance = new SingleInstance();
                }
            }
        }
        return signalInstance;
    }
}

Tags:

最近发表
标签列表