单例模式-双重检查锁定

public class MQThread extends Thread {
    // 私有静态实例,保证全局唯一
    private static volatile MQThread instance;
    // 获取单例实例的静态方法
    public static MQThread getInstance() {
        if (instance == null) {
            synchronized (MQThread.class) {
                if (instance == null) {
                    instance = new MQThread();
                }
            }
        }
        return instance;
    }
}

1. 代码功能

这段代码的作用是获取一个单例对象(MQThread 类的实例)。单例模式确保一个类只有一个实例,并提供一个全局访问点来获取这个实例。

2. 代码结构

2.1 public static MQThread getInstance()

这是一个静态方法,用于获取单例实例。static 表示该方法属于类,而不是类的某个对象实例,可以通过类名直接调用(如 MQThread.getInstance())。返回值是 MQThread 类型,表示返回的是一个 MQThread 对象。

2.2 if (instance == null)

这是双重检查锁定的第一层检查。instanceMQThread 类的一个静态变量,用于存储单例对象。这里先检查 instance 是否为 null,如果 instance 不为 null,说明单例对象已经创建,直接返回 instance,避免进入同步代码块,提高效率。

2.3 synchronized (MQThread.class)

这是一个同步代码块,用于确保线程安全。synchronized 是 Java 中的关键字,用于控制多个线程对共享资源的并发访问。这里将 MQThread 类的 Class 对象作为锁对象。当多个线程同时调用 getInstance() 方法时,只有一个线程可以进入同步代码块,其他线程必须等待当前线程执行完同步代码块后才能进入。

2.4 第二层检查 if (instance == null)

这是双重检查锁定的第二层检查。由于可能存在多个线程同时进入第一层检查的情况,当第一个线程进入同步代码块并创建了单例对象后,其他线程可能还在等待进入同步代码块。为了避免这些线程在进入同步代码块后再次创建单例对象,需要在同步代码块内再次检查 instance 是否为 null

2.5 instance = new MQThread();

如果 instancenull,说明单例对象尚未创建,此时创建单例对象并将其赋值给 instance 变量。

2.6 return instance;

返回单例对象。

3. 为什么使用双重检查锁定

单例模式的核心是确保一个类只有一个实例。如果不使用同步机制,多线程环境下可能会创建多个实例。但如果直接使用同步方法(如将整个 getInstance() 方法声明为 synchronized),会导致每次调用 getInstance() 方法时都进行同步操作,效率较低,尤其是当单例对象已经创建后,每次调用仍然需要同步。

双重检查锁定模式在第一次创建单例对象时使用同步机制,确保线程安全;在单例对象创建之后,直接返回单例对象,避免了同步操作,提高了效率。

4. 注意事项

  • instance 必须是 volatile:在 Java 中,volatile 关键字用于修饰变量,确保变量的读写操作对所有线程都是可见的。如果不使用 volatile,可能会出现指令重排序问题,导致线程看到未完全初始化的单例对象。因此,instance 变量应该声明为 volatile,例如:

private static volatile MQThread instance;
  • 类加载器问题:在某些复杂的环境下(如使用了多个类加载器),可能会导致单例模式失效。这是因为不同类加载器加载的类被认为是不同的类,即使它们的类名相同。在这种情况下,每个类加载器都会创建一个单例对象。

你可能感兴趣的:(Java基础,单例模式,java,数据结构)