懒汉单例模式《2》

1. 最简单的懒汉单例模式

/**
 * 1.  最简单的懒汉单例模式
 * 2.  将构造方法私有化,这样是防止在其他地方被实例化,就出现多个班长对象了
 * 3.  最后给外界提供一个方法,返回这个班长对象即可
 * 4. 不能保证线程安全问题
 */
public class SimpleLazySingleton {

    private static SimpleLazySingleton SIMPLE_LAZY_INSTANCE = null;

    private SimpleLazySingleton() {
    }

    public static SimpleLazySingleton getMonitor() {
        //如果两个线程同时到了判断null的地步,就会打破单例模式
        if (SIMPLE_LAZY_INSTANCE == null) {
            SIMPLE_LAZY_INSTANCE = new SimpleLazySingleton();
        }
        return SIMPLE_LAZY_INSTANCE;
    }

    public static void main(String[] args) {
        new Thread(new ExecutorThread()).start();
        new Thread(new ExecutorThread()).start();
        System.out.println("end");
    }
1.1 如何测试线程是否安全
/**
 * @author xiyou
 * 测试懒汉模式是否线程安全
 */
public class ExecutorThread implements Runnable {

    @Override
    public void run() {
        SimpleLazySingleton instance = SimpleLazySingleton.getMonitor();
        System.out.println(Thread.currentThread().getName() + ":" + instance);
    }
}

    public static void main(String[] args) {
        new Thread(new ExecutorThread()).start();
        new Thread(new ExecutorThread()).start();

    }

测试结果:

1. 相同情况:(也会有线程安全问题,第一个结果会被第二个结果覆盖)
Thread-0:cn.net.health.tools.design.single.lazy.SimpleLazySingleton@3abf0e6c
Thread-1:cn.net.health.tools.design.single.lazy.SimpleLazySingleton@3abf0e6c
2. 线程不安全情况
Thread-1:cn.net.health.tools.design.single.lazy.SimpleLazySingleton@b91ca14
Thread-0:cn.net.health.tools.design.single.lazy.SimpleLazySingleton@5d52c55b
1.2 如何多线程打断点

A:多线程环境下,执行结果是相同实例

  1. 顺序执行线程安全

  2. 不是顺序执行,线程同时进入if判断,后者创建的实例会覆盖前者,2个打印的结果是后者创建的实例

    如何多线程打断点,可以百度下,这里要说的是两个线程的断点要打到哪个地方?

    对于A2的情况,只要把两个线程的断点都打到 monitor = new Monitor();但是都不进行下一步,然后把第一个线程放开,会创建单例1但是不进行return monitor的操作,然后放开线程2,会创建单例2,然后单例2会把单例1 覆盖掉

B: 结果不一致的情况

对于B的情况,只要把两个线程的断点都打到 monitor = new Monitor();但是都不进行下一步,然后把第一个线程放开,会创建单例1然后让线程1走完全程并打印,然后放开线程2,就会出现不一致的情况

2. 线程安全的懒汉单例模式

/**
 * @author xiyou
 * 1. 相对于SimpleLazySingleton多了一个synchronized 线程安全了
 * 2.  但是效率太差了,不管班长对象有没有被创建好,后面每个线程并发走到这,无用等待太多了
 */
public class SyncLazySingleton {

    private static SyncLazySingleton SYNC_LAZY_INSTANCE = null;

    private SyncLazySingleton() {
    }

    public synchronized static SyncLazySingleton getMonitor() {
        if (SYNC_LAZY_INSTANCE == null) {
            SYNC_LAZY_INSTANCE = new SyncLazySingleton();
        }
        return SYNC_LAZY_INSTANCE;
    }
}

3. 双重校验DDL懒汉单例模式(线程非安全)

/**
 * @author xiyou
 * 1. 这个双重判断看似线程安全,但还是有线程安全问题
 */
public class DoubleCheckLazySingleton {

    private static DoubleCheckLazySingleton DOUBLE_CHECK_LAZY_INSTANCE = null;

    private DoubleCheckLazySingleton() {
    }

    public static DoubleCheckLazySingleton getMonitor() {
        //外层判断用来判断是否要阻塞线程,提高效率,外层的可以去掉,但是会影响效率
        if (DOUBLE_CHECK_LAZY_INSTANCE == null) {
            synchronized (DoubleCheckLazySingleton.class) {
                //内存判断是否要创建线程,保证线程安全,这个不能去掉,去掉线程不安全
                if (null == DOUBLE_CHECK_LAZY_INSTANCE) {
                    DOUBLE_CHECK_LAZY_INSTANCE = new DoubleCheckLazySingleton();
                }
            }
        }
        return DOUBLE_CHECK_LAZY_INSTANCE;
    }

}

4. Volatile双重校验线程安全的懒汉单例模式

只是比上面多了一个volatile关键字

/**
 * @author xiyou
 * /*
 * 1. 最终版本的懒汉单例模式
 * 2. 双重校验的volatile懒汉单例模式
 * 3. 添加volatile 是为了防止类初始化的时候出现问题
 * 4. 类初始化顺序:monitor =new Monitor();
 * 3.1 在堆内存分配空间
 * 3.2 把Monitor的构造方法初始化
 * 3.3 把monitor对象指向在堆空间分配好的地址空间
 * 5. 在多线程条件下,3.2 和3.3的顺序可能互调,volatile就说为了解决这个问题的
 * 6. 故 它是线程安全的
 */
public class DoubleCheckVolatileLazySingleton {

    private static volatile DoubleCheckVolatileLazySingleton DOUBLE_CHECK_VOLATILE_LZY_INSTANCE = null;

    private DoubleCheckVolatileLazySingleton() {
    }

    public static DoubleCheckVolatileLazySingleton getMonitor() {
        //外层判断用来判断是否要阻塞线程,提高效率,外层的可以去掉,但是会影响效率
        if (DOUBLE_CHECK_VOLATILE_LZY_INSTANCE == null) {
            synchronized (DoubleCheckVolatileLazySingleton.class) {
                //内存判断是否要创建线程,保证线程安全,这个不能去掉,去掉线程不安全
                if (null == DOUBLE_CHECK_VOLATILE_LZY_INSTANCE) {
                    DOUBLE_CHECK_VOLATILE_LZY_INSTANCE = new DoubleCheckVolatileLazySingleton();
                }
            }
        }
        return DOUBLE_CHECK_VOLATILE_LZY_INSTANCE;
    }

}

5. 太复杂?有没有简单的?静态内部类实现

请翻看相关博文

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值