Java双重校验锁单例原理攻略
在Java中,单例模式是一种常见的设计模式,用于确保一个类只有一个实例,并提供全局访问点。其中,双重校验锁是一种常用的实现方式,它结合了懒加载和线程安全的特性。本攻略将详细讲解Java双重校验锁单例的原理,并提供两个示例说明。
原理解析
双重校验锁单例模式的核心思想是在保证线程安全的前提下,尽可能地减少锁的使用,以提高性能。它的实现过程如下:
- 私有化构造函数:将类的构造函数私有化,使得其他类无法直接实例化该类。
- 声明一个私有的静态变量:用于保存单例实例。
- 提供一个公共的静态方法:用于获取单例实例。
- 双重校验锁:在公共方法中使用双重校验锁,确保只有第一次调用时才会创建实例。
下面是一个示例代码:
public class Singleton {
private volatile static Singleton instance;
private Singleton() {
// 私有化构造函数
}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
在上述代码中,volatile
关键字用于确保多线程环境下的可见性,避免指令重排序导致的问题。双重校验锁的关键在于两次判断instance
是否为null,第一次判断是为了避免不必要的同步开销,第二次判断是为了在实例创建之前,避免其他线程已经创建了实例。
示例说明
示例一:多线程环境下的单例模式
public class Singleton {
private volatile static Singleton instance;
private Singleton() {
// 私有化构造函数
}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
public class Main {
public static void main(String[] args) {
Runnable task = () -> {
Singleton singleton = Singleton.getInstance();
System.out.println(\"Thread: \" + Thread.currentThread().getName() + \", Singleton: \" + singleton);
};
// 创建多个线程并同时获取单例实例
Thread thread1 = new Thread(task);
Thread thread2 = new Thread(task);
thread1.start();
thread2.start();
}
}
在上述示例中,我们创建了两个线程并同时获取单例实例。由于双重校验锁的存在,只会有一个线程创建实例,其他线程会等待。输出结果类似于:
Thread: Thread-0, Singleton: Singleton@1a2b3c4d
Thread: Thread-1, Singleton: Singleton@1a2b3c4d
可以看到,两个线程获取到的实例是相同的,符合单例模式的要求。
示例二:延迟加载的单例模式
public class Singleton {
private volatile static Singleton instance;
private Singleton() {
// 私有化构造函数
}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
public class Main {
public static void main(String[] args) {
Singleton singleton1 = Singleton.getInstance();
Singleton singleton2 = Singleton.getInstance();
System.out.println(\"Singleton1: \" + singleton1);
System.out.println(\"Singleton2: \" + singleton2);
}
}
在上述示例中,我们直接调用getInstance
方法获取单例实例。由于双重校验锁的存在,实例只会在第一次调用时创建,之后的调用会直接返回已创建的实例。输出结果类似于:
Singleton1: Singleton@1a2b3c4d
Singleton2: Singleton@1a2b3c4d
可以看到,两次获取到的实例是相同的,符合单例模式的要求。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java双重校验锁单例原理 - Python技术站