并发编程下的单例设计模式

2023-09-30 19:48:11 浏览数 (1)

饿汉式

代码语言:java复制
/**
 * @author BNTang
 */
public class Singleton {
    /**
     * 没有延迟加载,好长时间不使用,影响性能
     */
    private static Singleton instance = new Singleton();

    private Singleton() {
    }

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

特点

  • 线程安全性: 在加载的时候已经被实例化,所以只有这一次是线程安全的
  • 懒加载: 没有延迟加载,好长时间不使用,影响性能

懒汉式 同步方法

代码语言:java复制
/**
 * @author BNTang
 */
public class SingletonTwo {
    private static SingletonTwo instance = null;

    private SingletonTwo() {
    }

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

特点

  • 直接在方法上进行加锁
  • 锁的力度太大,性能不是太好
  • synchronized,退化到了串行执行

Double-Check-Locking

代码语言:java复制
/**
 * @author BNTang
 */
public class SingletonThree {
    private static volatile SingletonThree instance = null;

    private SingletonThree() {
    }

    public static SingletonThree getInstance() {
        // Double-Check-Locking, DCL
        if (instance == null) {
            synchronized (SingletonThree.class) {
                if (instance == null) {
                    instance = new SingletonThree();
                }
            }
        }
        return instance;
    }
}

特点

  • 保证了线程安全
  • 如果实例中存在多个成员属性,由于在代码执行过程当中, 会对代码进行重排, 重排后, 可能导致另一个线程获取对象时初始化属性不正确的情况

加 volatile

创建对象步骤

代码语言:text复制
memory = allocate();   // 1:分配对象的内存空间
ctorInstance(memory);  // 2:初始化对象
instance = memory;     // 3:设置 instance 指向刚分配的内存地址
代码语言:text复制
memory = allocate();   // 1:分配对象的内存空间
instance = memory;     // 3:设置 instance 指向刚分配的内存地址
                       //    注意,此时对象还没有被初始化!
ctorInstance(memory);  // 2:初始化对象

重排问题

Holder

代码语言:java复制
/**
 * @author BNTang
 */
public class SingletonFour {
    private SingletonFour() {
        System.out.println("SingletonFour 初始化了");
    }

    /**
     * 第一次使用到的时候才去执行, 只执行一次
     */
    private static class Holder {
        private static SingletonFour instance = new SingletonFour();
    }

    public static SingletonFour getInstance() {
        return Holder.instance;
    }
}

特点

  • 它结合了饿汉模式, 安全性,也结合了懒汉模式懒加载。不会使用 synchronized 所以性能也有所保证
  • 声明类的时候,成员变量中不声明实例变量,而放到内部静态类中
  • 不存在线程安全问题
  • 懒加载

反序列化问题

代码语言:java复制
// 该方法在反序列化时会被调用
protected Object readResolve() throws ObjectStreamException {
    System.out.println("调用了readResolve方法!");
    return Holder.instance;
}

枚举的方式创建单例

代码语言:java复制
/**
 * @author BNTang
 */
public enum SingletonFive {
    /**
     * 单值的枚举就是一个单例
     */
    INSTANCE;
    private static int a = 0;
    
    public static void add() {
        a  ;
        System.out.println(a);
    }
    
    public static SingletonFive getInstance() {
        return INSTANCE;
    }
}

特点

  • 不存在线程安全问题
  • 没有懒加载

enum 加延迟加载方式

代码语言:java复制
/**
 * @author BNTang
 */
public class SingletonSix {
    private SingletonSix() {
    }

    private enum Holder {
        INSTANCE;
        private SingletonSix instance = null;

        Holder() {
            instance = new SingletonSix();
        }

        private SingletonSix getInstance() {
            return instance;
        }
    }

    public static SingletonSix getInstance() {
        return Holder.INSTANCE.getInstance();
    }
}

特点

  • 没有线程安全问题
  • 懒加载

源码

Runtime 类

Mybatis ErrorContext

类加载器

我正在参与2023腾讯技术创作特训营第二期有奖征文,瓜分万元奖池和键盘手表

0 人点赞