网站如何推广方式,区块链开发公司,找网络推广策畿,wordpress仿内涵段子目录 ♫什么是单例模式 ♫饿汉式单例模式 ♫懒汉式单例模式 ♫单例模式的线程安全问题
♪原子性
♪内存可见性与指令重排序 ♫什么是单例模式 单例模式是一种设计模式#xff0c;通过巧用Java的现有语法#xff0c;实现一个只能被创建一个实例的类#xff0c;并提供一个全…目录 ♫什么是单例模式 ♫饿汉式单例模式 ♫懒汉式单例模式 ♫单例模式的线程安全问题
♪原子性
♪内存可见性与指令重排序 ♫什么是单例模式 单例模式是一种设计模式通过巧用Java的现有语法实现一个只能被创建一个实例的类并提供一个全局访问点。在有些创场景中一些特点的类只能创建一个实例虽然不依赖单例模式我们也可以控制类的实现个数但通过单例模式实现的类就相当于有了语法约束即使想要实现多个实例都很难。在Java中单例模式的实现有多种方式下面是两种比较常用的实现方式。 ♫饿汉式单例模式 饿汉式单例模式是指在类加载时就创建实例对象通过static关键字保证在程序的整个生命周期中只存在一个实例对象 public class Singleton {// 静态成员变量用来记录唯一实例private static Singleton uniqueInstance new Singleton();// 私有构造方法防止外部通过new关键字创建实例private Singleton() {}// 静态工厂方法返回唯一实例public static Singleton getInstance() {return uniqueInstance;}
} 通过将构造方法设置为私有的保证类外无法通过new来创建实例的同时通过static将uniqueInstance成员属性修饰为类属性Java代码中的每个类在编译完成后都会生成.class文件JVM加载时通过读取.class文件中的二进制指令来在内存中构造出类对象Singleton.class类对象的属性就是类属性由于类对象只有一份故类属性也就只有一份。 ♫懒汉式单例模式 懒汉式单例模式是指在第一次访问时才创建实例对象在第一次访问之前则不创建对象 public class Singleton {// 静态成员变量用来记录唯一实例private static Singleton uniqueInstance null;// 私有构造方法防止外部通过new关键字创建实例private Singleton() {}// 静态工厂方法返回唯一实例public static synchronized Singleton getInstance() {if (uniqueInstance null) {uniqueInstance new Singleton();}return uniqueInstance;}
} 懒汉模式与饿汉模式的区别在于懒汉模式只有在第一次使用时才创建实例对象不使用则不创建实例对象而饿汉模式则不管有没有使用都会在使用前类加载时创建一个实例对象。 ♫单例模式的线程安全问题 在多线程环境下饿汉模式只有到读操作不需要考虑线程安全问题而懒汉模式既有读又有写这就得涉及到线程安全了。 1.在if语句中可以分为读、比较、写三步由于这三步骤不是原子性的在多线程环境下就可能发生第一个线程读完还未写入前第二个线程也开始读从而导致可能多次执行new操作。 ♪原子性 我们可以通过synchronized来保证读、比较、写的原子性 //懒汉模式
class Singleton2 {private static Singleton2 uniqueInstance null;public Singleton2 getInstance() {synchronized (Singleton2.class) {if (uniqueInstance null) {uniqueInstance new Singleton2();}}return uniqueInstance;}private Singleton2() {}
} 虽然通过给类对象加锁保证了if语句的原子性但这样写每一次使用都需要进行加锁操作加大了开销故我们还可以在加锁前再判断下需不需要进行加锁操作 //懒汉模式
class Singleton2 {private static Singleton2 uniqueInstance null;public Singleton2 getInstance() {if (uniqueInstance null) {synchronized (Singleton2.class) {if (uniqueInstance null) {uniqueInstance new Singleton2();}}}return uniqueInstance;}private Singleton2() {}
}注第一个if判断是否需要加锁第二个if判断是否需要创建对象 ♪内存可见性与指令重排序 懒汉模式不仅有原子性问题还有内存可见性与指令重排序的隐患 ♩内存可见性在多线程环境下有多个线程同时进行getInstance操作有可能编译器只有第一次是从内存中读取uniqueInstance的值其它时候都是直接从寄存器或cache中读取uniqueInstance的值也会导致多次创建实例对象。 ♩指令重排序uniqueInstancenew Singleton2()操作可以拆分为三步①.申请内存空间②.调用构造方法在内存空间上创建一个实例对象③.把内存空间的值赋值给uniqueInstance。正常情况下顺序执行①②③是没有问题的但无法保证编译器不会优化这三步骤的执行顺序若是执行顺序为①③②那么就可能在一个线程执行到②之前就调度去另一个线程执行①这就会导致内存空间后面被初始化而该线程就以为对象创建好了如果这时候这个线程使用对象的属性方法就会出现问题。 解决内存可见性与指令重排序就需要给uniqueInstance加上volatile关键字 //懒汉模式
class Singleton2 {private static volatile Singleton2 uniqueInstance null;public Singleton2 getInstance() {if (uniqueInstance null) {synchronized (Singleton2.class) {if (uniqueInstance null) {uniqueInstance new Singleton2();}}}return uniqueInstance;}private Singleton2() {}
}