外贸品牌网站设计公司,广东建设厅网站查询,提升网站权重的策略,网站建设与实现毕业答辩ppt一、双重检查锁定#xff08;Double-Checked Locking#xff09; 这种设计模式的目的是为了减少在多线程环境下获取锁的开销#xff0c;尤其是当实例化对象的操作很昂贵#xff0c;且该对象只会被实例化一次时。双重检查锁定模式的基本思想是#xff0c;在创建对象之前进行…一、双重检查锁定Double-Checked Locking 这种设计模式的目的是为了减少在多线程环境下获取锁的开销尤其是当实例化对象的操作很昂贵且该对象只会被实例化一次时。双重检查锁定模式的基本思想是在创建对象之前进行两次检查首先无锁地检查实例是否已经创建如果未创建才进行加锁再次检查实例是否已创建如果仍未创建则在同步块内实例化对象。 然而在早期的Java内存模型JMM中这段看似高效的代码存在一些问题主要体现在以下几点 1. 指令重排序编译器或处理器为了优化性能可能会对代码执行顺序进行重新排序。在双重检查锁定模式中即使实例化的代码在同步块内对象的字段初始化和对象引用的赋值操作仍可能被重排序。这意味着其他线程有可能在对象完全构造完成前就看到对象引用从而访问到一个部分构造的对象导致不可预料的行为。 2. 可见性问题没有使用volatile关键字修饰实例变量时新创建的对象实例可能不会立即对其他线程可见导致其他线程看到的是旧的值即null即使对象已经被正确初始化。 为了解决这些问题通常采取以下措施 3. 使用volatile关键字确保对实例变量的写操作之前的所有操作都先行发生且该写操作之后的所有读操作都能看到这个写的结果。这解决了指令重排序和可见性问题。 修正后的双重检查锁定模式示例代码如下
/*** Singleton类的实例化方法。保证线程安全的单例模式实现。* 采用双重检查锁定的方式避免多次实例化保证线程安全。* * return 返回Singleton类的唯一实例。*/
public static Singleton getInstance() {// 如果实例尚未创建则进入同步块if(instance null){synchronized(Singleton.class){// 在同步块内部再次检查实例是否存在避免不必要的锁定if(instance null){instance new Singleton();}}}return instance;
}这段代码中包含了一个静态的、volatile修饰的Singleton实例这是为了确保在多线程环境下实例的创建是线程安全的。使用双重检查锁定的方式在实例未被创建时对访问进行同步以确保只有一个线程能够创建实例。这种方式既避免了线程安全问题又尽可能地降低了同步的开销。
尽管使用volatile和双重检查锁定可以有效解决上述问题但在现代Java实践中推荐使用基于类加载机制的静态内部类方式来实现单例模式因为这种方式既简洁又避免了双重检查锁定可能带来的复杂性。
二、 基于类加载机制的静态内部类单例模式
基于类加载机制的静态内部类单例模式是一种非常简洁且线程安全的方式它利用了Java类加载机制来确保单例的唯一性。以下是该模式的示例代码
/*** 一个使用静态内部类实现的单例类。这种实现方式保证了线程安全并且在类加载时才初始化单例* 实现了延迟初始化lazy initialization。*/
public class Singleton {/*** 私有构造函数防止外部直接实例化Singleton类。*/private Singleton() {}/*** 静态内部类SingletonHolder用于持有Singleton的唯一实例。这种方式确保Singleton实例在需要时才被创建* 且由于类加载机制其创建过程是线程安全的。*/private static class SingletonHolder {private static final Singleton INSTANCE new Singleton();}/*** 获取Singleton类的唯一实例。调用此方法将返回Singleton的实例首次调用时实例才会被创建。** return Singleton类的唯一实例。*/public static Singleton getInstance() {// 直接返回SingletonHolder类中持有的Singleton实例实现延迟初始化和线程安全return SingletonHolder.INSTANCE;}
}在这个例子中Singleton 类包含一个私有的静态内部类 SingletonHolder。SingletonHolder 类中有一个静态常量 INSTANCE用于持有 Singleton 的单例实例。由于静态内部类只有在外部类首次被加载时才会被加载而类加载是线程安全的因此 Singleton 的实例化过程也是线程安全的。 当调用 Singleton.getInstance() 方法时会直接返回 SingletonHolder.INSTANCE而不需要进行任何同步操作。这样既保证了单例的线程安全性又避免了使用 synchronized 或 ReentrantLock 带来的额外开销。
这种方式不仅保证了线程安全性而且通过延迟初始化lazy initialization提高了效率因为Singleton实例只有在第一次调用getInstance()时才会被创建。同时由于静态内部类的特性它的加载是在第一次被引用时才会发生因此避免了类加载时就初始化单例的问题。这种实现方式的优点在于线程安全由于类加载过程是线程安全的所以无需担心并发问题。延迟初始化单例实例只在 getInstance 被第一次调用时创建实现了延迟初始化。代码简洁没有使用锁或其他同步机制代码更简洁易懂。 请注意这种方式适用于不需要在类加载时就初始化单例的场景。如果单例需要在类加载时就初始化那么应选择其他实现方式例如枚举单例。
三、枚举单例
枚举单例是Java中实现单例模式的一种优雅且线程安全的方式。这种方式利用了Java枚举的特性使得单例在类加载时自动初始化而且无法通过反射或其他方式破坏其唯一性。以下是一个简单的枚举单例模式的示例
public enum Singleton {INSTANCE;// 可以添加方法和其他属性private String someProperty Some value;public String getSomeProperty() {return someProperty;}public void setSomeProperty(String value) {this.someProperty value;}
}在这个例子中Singleton 是一个枚举类型只有一个元素 INSTANCE。这个元素就是单例的实例。由于枚举在Java中是唯一的不能被实例化多次因此保证了单例的唯一性。同时枚举的初始化是在类加载时完成的因此是线程安全的。 要使用这个单例只需调用 Singleton.INSTANCE就像访问枚举常量一样
Singleton singleton Singleton.INSTANCE;
System.out.println(singleton.getSomeProperty());枚举单例的优点包括线程安全Java保证了枚举实例的创建是线程安全的。懒加载尽管枚举在类加载时初始化但由于枚举的静态特性实际上只在第一次访问时才会触发枚举实例的创建。防止反射攻击枚举实例不能通过反射创建增强了单例的安全性。 简单明了代码简洁易于理解和维护。 这种实现方式是Joshua Bloch在《Effective Java》一书中推荐的单例实现方法。