沧州响应式网站开发,昆明做网站建设找谁,如何建设数据报表网站,创建网站的注意事项《Effective Java》中的第3条编程法则主要是针对在开发过程如何实现单例模式#xff0c;作者 Joshua Bloch 在书中给出了3种单例模式的实现方式#xff1a;私有构造器和公有静态域、私有构造器和公有静态方法、枚举式。
什么是单例模式#xff1f;
单例模式是一种设计模式…《Effective Java》中的第3条编程法则主要是针对在开发过程如何实现单例模式作者 Joshua Bloch 在书中给出了3种单例模式的实现方式私有构造器和公有静态域、私有构造器和公有静态方法、枚举式。
什么是单例模式
单例模式是一种设计模式旨在确保一个类只有一个实例其主要目的是控制类的实例化过程避免创建多个对象实例并提供一个全局访问点来获取该实例。这种模式适用于需要唯一对象来协调全局操作或资源管理的场景例如配置管理器、线程池等。
单例实现方式
实现方式一私有构造器和公有静态域饿汉式单例模式
通过私有构造器和公有静态域实现单例模式是一种简单且直接的方法这种实现通常被称为饿汉式单例模式。
public class Singleton {// 单例对象在类加载时创建public static final Singleton INSTANCE new Singleton();// 私有构造器防止外部实例化private Singleton() {// 可以添加初始化代码}// 其他方法public void doSomething() {// 实现具体的业务逻辑}
}在这种实现中通过将构造器设为 private类外部无法直接创建实例从而确保了单例模式的唯一性。而 static final 修饰符确保了在类加载阶段就创建并初始化实例并且实例一旦创建后不可变这样就进一步保证了单例实例的唯一性和一致性。整体设计既简单又有效。
实现方式二私有构造器和公有静态方法懒汉式单例模式 双重检查锁定
私有构造器和公有静态方法的实现通常称为懒汉式单例模式
public class Singleton {private static Singleton instance;private Singleton() {// 私有构造器}public static synchronized Singleton getInstance() {if (instance null) {instance new Singleton();}return instance;}
}相比饿汉式单例模式实例的创建时机固定懒汉式的实现将实例的初始化延迟到在第一次调用 getInstance 方法时创建这样可以避免在程序启动时就初始化实例从而节省资源。
但是在懒汉式的实现中使用了synchronized 关键字保证在多线程环境下对 getInstance 方法的访问是线程安全的。然而这种实现方式的缺点是每次调用 getInstance 方法时都要进行同步这会带来性能开销。
幸运的是由于我们使用静态工厂方法创建类的实例那么我们就可以在方法种控制创建实例的时机即在懒汉式单例模式的基础上进行优化减少同步的开销来提高效率
在获取实例时首先检查实例是否已存在如果已存在则直接返回该实例。如果实例不存在再进行同步检查以确保实例初始化的线程安全。
public class Singleton {// 使用 volatile 关键字确保线程安全private static volatile Singleton instance;// 私有构造器防止外部实例化private Singleton() {// 私有构造器}// 提供公共的静态方法获取实例public static Singleton getInstance() {if (instance null) { // 第一次检查synchronized (Singleton.class) {if (instance null) { // 第二次检查instance new Singleton();}}}return instance;}
}这种优化在获取实例时引入了两次检查因此也被称为双重检查锁定
第一次检查在同步块外部进行以减少不必要的同步开销。第二次检查在同步块内部进行以确保实例的唯一性。
实现方式三枚举式
由于枚举类型本身设计用于定义一组常量因此实现单例模式时通常一个枚举类型中只定义一个枚举实例
public enum Singleton {INSTANCE;public void doSomething() {// 实现具体功能}
}饿汉式 VS 懒汉式 VS 枚举式
饿汉式和懒汉式单例模式的实现在反序列化和反射攻击可能会导致创建多个实例破坏单例模式的唯一性。因此还需要添加以下处理 实现 readResolve 方法确保在反序列化过程中获取的对象仍然是单例实例而不是新的实例 private Object readResolve() {return getInstance();
}在构造函数中增加检查防止通过反射创建多个实例 private Singleton() {if (instance ! null) {throw new RuntimeException(Use getInstance() method to get the single instance of this class.);}
}枚举由于自身的特殊机制使得枚举式相比前两者更适合单例模式得实现
天然的线程安全Java 枚举类型的实例在 JVM 加载时会创建一次且只创建一次整个加载过程是线程安全的。因此不需要额外的同步来保证线程安全。防止反序列化攻击枚举的实例由 JVM 管理序列化和反序列化过程中保持唯一性。这意味着即使序列化和反序列化操作被恶意操控也不会生成新的实例。防止反射攻击枚举类型的构造函数是私有的当尝试使用反射创建枚举实例会抛出 IllegalArgumentException 异常从而保护了单例的唯一性。
这也是 Joshua Bloch 在书中提到单元素的枚举类型经常成为实现 Singleton 的最佳方法的原因。