单例模式

单例模式是Java中最简单的设计模式之一,而且用途也比较多,比如说各种池,回收站等等。单例模式的特点是保证一个类只有一个实例。下面给大家介绍一下常用的单例模式写法。

原文链接:https://blog.csdn.net/qq_35098526/java/article/details/79893628

饿汉式

public class EHanSingletonTest {
    /**
          *是否 Lazy 初始化:否
          *是否多线程安全:是
          *实现难度:易
          *描述:这种方式比较常用,但容易产生垃圾对象。
          *优点:没有加锁,执行效率会提高。
          *缺点:类加载时就初始化,浪费内存。
          *它基于 classloder 机制避免了多线程的同步问题,
          * 不过,instance 在类装载时就实例化,虽然导致类装载的原因有很多种,
          * 在单例模式中大多数都是调用 getInstance 方法,
          * 但是也不能确定有其他的方式(或者其他的静态方法)导致类装载,
          * 这时候初始化 instance 显然没有达到 lazy loading 的效果。
          */

    private static EHanSingletonTest instance = new EHanSingletonTest();
    private EHanSingletonTest() {

    }
    public static EHanSingletonTest getInstance() {
        return instance;
    }
}

 

懒汉式:

 

public class LHSingletonTest {
    /**
          *是否 Lazy 初始化:是
          *是否多线程安全:否
          *实现难度:易
          *描述:这种方式是最基本的实现方式,这种实现最大的问题就是不支持多线程。因为没有加锁 synchronized,所以严格意义上它并不算单例模式。
          *这种方式 lazy loading 很明显,不要求线程安全,在多线程不能正常工作。
          */

    private static LHSingletonTest instance = null;
    private LHSingletonTest() {

    }
    public static LHSingletonTest getInstance() {
        if(instance == null) {
            instance = new LHSingletonTest();
        }
        return instance;
    }
}

 

双层锁式懒汉式

/**
 * 双重锁式线程安全的单例模式
 */
public class SafeLHSingletonTest {
    private static volatile SafeLHSingletonTest instance = null;
    private SafeLHSingletonTest() {

    }

    public static SafeLHSingletonTest getInstance() {
        if(instance == null) {
            synchronized (instance) {
                if(instance == null) {
                    instance = new SafeLHSingletonTest();
                }
            }
        }
        return instance;
    }
}

特点:

1、使用双层锁式,对比锁住整个方法,这样保证了第二次获取instance有值的时候就不会进入synchronized方法。

2、使用volatile,禁止了重排序,new实例的时候有三个步骤。

1.给instance分配空间、
2.调用 Singleton 的构造函数来初始化、
3.将instance对象指向分配的内存空间(instance指向分配的内存空间后就不为null了);

jvm可能进行重排序,1-3-2,在分配完空间,执行完3,还没执行2,还没初始化完成的时候,线程2就进入了第一个if()判断,然后直接instance不为空,会出现问题。

volatile禁止重排序,保证可见性,每次读取变量都会去主内存中读取最新的变量。

 

posted @ 2020-05-26 14:17  BBI丨BBI  阅读(94)  评论(0)    收藏  举报