单例模式

单例模式

一种设计模式,用该模式设计的类,只能创建出一个实例

  • 场景:
    • Spring: 一个Component就只有一个实例
    • JavaWeb: 一个Servlet只有一个实例
    • 文件系统: 一个操作系统只能有一个文件系统

实现

用到较多的单例模式实现方式:饿汉式、懒汉式、双重检测锁、静态内部类。

  • 实现要点:
    • 隐藏构造器
    • static Singleton实例
    • 暴露实例的获取方法
  • 追求的目标
    • 线程安全
    • 调用效率高
    • 延迟加载

1、饿汉式

/**
 *
 * @description: 饿汉式
 * @author: huang xin
 * @create: 2018-10-25 20:46
 */
public class HungerSingleton {

    private HungerSingleton(){}  //构造函数私有化,不能在类的外部创建该类的实体

    /*
    *   在类加载时候就创建了对象,天然的线程安全
    *   问题:没有调用方法创建对象,造成资源浪费
    * */
    private static final HungerSingleton singleton = new HungerSingleton();

    /*
    *   静态方法直接返回静态变量,方法没有同步(synchronized),调用效率高
    * */
    public static HungerSingleton getInstance(){
        return singleton;
    }
}

2、懒汉式

/**
 * @description: 懒汉式
 * @author: huang xin
 * @create: 2018-10-25 21:04
 */
public class LazySingleton {
    /*
    *   懒汉式,顾名思义是类加载是不创建对象,而是调用getInstance()时创建对象
    *   问题:需要考虑线程同步,效率低
    * */

    private LazySingleton(){} //构造器隐藏起来

    /*
    *   类加载时没有初始化,延迟加载
    *   不能声明为final,因为getInstance()需要singleton赋值
    * */
    private static LazySingleton singleton ;

    /*
    *   在方法上加上线程同步(synchronized)
    *   弊端:第二次以后获取单例对象,都要进入锁。耗时
    * */
    public static synchronized LazySingleton getInstance(){
        if (null == singleton){ //第一次创建后,不在创建
            singleton = new LazySingleton();
        }
        return singleton;
    }
}

3、双重检测锁

双重检测锁是懒汉式的优化,避免每次实例化都会同步(synchronized)耗时,加入两个if判断。

/**
 * @description: 双重检测锁,适用于JDK1.5之后的版本
 * @author: huang xin
 * @create: 2018-10-25 21:29
 */
public class DoubleCheckSingleton {

    private DoubleCheckSingleton(){}

   /*
    * 需要使用volatile
    * 保证所有的写(write)都将先行发生于读(read)
   * */
    private static volatile DoubleCheckSingleton singleton;

/*
*   只在第一次实例化进入锁
*   优点:可以达到延迟加载的要求,调用效率高
* */
    public static DoubleCheckSingleton getInstance(){
        if (singleton == null){       //第一次检测;存在实例就不进入
            synchronized (DoubleCheckSingleton.class){
                if (singleton == null){      //第二次检测:防止B线程在获得A线程释放的锁后重入
                    singleton = new DoubleCheckSingleton();
                }
            }
        }
        return singleton;
    }
}

4、静态内部类

/**
 * @description: 静态内部类实现
 * @author: huang xin
 * @create: 2018-10-25 21:48
 */
public class StaticClassSingleton {
    /*
    *   外部类没有static属性,因此加载本类时不会立即初始化对象
    * */
    private static final class InnerClassSingleton{
        private static final StaticClassSingleton singleton = new StaticClassSingleton();
    }

    private StaticClassSingleton(){} //构造器隐藏,但内部类可访问的到
    /*
    * 有真正调用getInstance方法时, 才会加载静态内部类(延迟加载),
    * 而且加载类是天然的线程安全的(线程安全), 没有synchronized(调用效率高)
    * */
    public static StaticClassSingleton getInstance(){
        return InnerClassSingleton.singleton;  //访问内部类的属性
    }
}

实现对比

方式优点缺点
懒汉式线程安全, 可以延迟加载调用效率不高
恶汉式线程安全, 调用效率高不能延迟加载
双重检测锁线程安全, 调用效率高, 可以延迟加载
静态内部类线程安全, 调用效率高, 可以延迟加载
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值