设计模式系列—单例设计模式( 二 )


这种单例模式可用 , 但是如果不用 , 可能会造成内存的浪费 。
懒汉式(线程不安全)代码示例package com.niuh.designpattern.singleton.v3;/** * * 懒汉式(线程不安全) */public class Singleton {private static Singleton instance;// 构造函数私有化private Singleton() {}// 提供一个静态的公共方法 , 当使用到该方法时 , 才创建 instance , 即懒汉式public static Singleton getInstance() {if (instance == null) {instance = new Singleton();}return instance;}}class SingletonTest02 {public static void main(String[] args) {// 测试for (int i = 0; i< 100; i++) {new Thread(() ->System.out.println(Singleton.getInstance().hashCode())).start();}}}优缺点

  • 起到了 懒加载 的效果 , 但是只能在 单线程下使用;
  • 如果在多线程下 , 一个线程进入了 if(instance == null) 判断语句块 , 可能另外一个线程也通过了这个语句判断 , 这是会产生多个实例 , 所以在多线程环境下不可使用这种方式 。
【设计模式系列—单例设计模式】在实际开发中 , 不要使用这种方式 。
懒汉式(线程安全 , 同步方法)代码示例/** * 懒汉式(线程安全 , 同步方法) */public class Singleton {private static Singleton instance;// 构造函数私有化private Singleton() {}// 提供一个静态的公有方法 , 加入同步处理的代码 , 解决线程安全问题public static synchronizedSingleton getInstance() {if (instance == null) {instance = new Singleton();}return instance;}}注:加入关键字保证线程安全问题 synchronized
优缺点
  • 虽然加入保证线程安全的关键字 , 解决线程安全问题(其实实际上并不一定线程安全:编译器(JIT),CPU 有可能对指令进行重排序)
  • 效率低下 , 每个线程在想获得实例的时候 , 执行 getInstance 方法都要进行同步 。 方法的同步效率太低 。
在实际开发中 , 不推荐这种方式
懒汉式(线程安全 , 同步代码块)代码示例/** * 懒汉式(线程安全 , 同步代码块) */public class Singleton {private static Singleton instance;// 构造函数私有化private Singleton() {}// 提供一个静态的公有方法 , 加入同步处理的代码 , 解决线程安全问题public static Singleton getInstance() {if (instance == null) {synchronized (Singleton.class) {instance = new Singleton();}}return instance;}}优缺点虽然对加锁处做了一定优化 , 总体优缺点同上面一致 。
双重检查(DCL)代码示例/** * 双重检查 DCL */public class Singleton {// 添加 volatile 关键字 , 防止指令重排private static volatile Singleton instance;// 构造函数私有化private Singleton() {}// 提供对外引用的静态方法 , 使用双重检查机制 double checkpublic static Singleton getInstance() {if (instance == null) { // Double Check Lock// 双重检查synchronized (Singleton.class) {if (instance == null) {instance = new Singleton();}}}return instance;}}编译器(JIT),CPU 有可能对指令进行重排序 , 导致使用到尚未初始化的实例 , 可以通过添加volatile 关键字进行修饰
优缺点
  • Double-Check 概念是多线程开发中常使用到的 , 如代码中所示 , 我们进行了两次 if(singleton== null) 检查 , 这样就可以保证线程安全了
  • 实例化代码只用执行一次 , 后面在进行访问的时候 , 判断 if(singleton== null) , 直接 return 实例化对象 , 也避免了反复进行方法同步 。
最重要的是 线程安全 , 延迟加载 , 效率高 在实际开发中 , 推荐使用这种单例设计模式