八股整理xdsm - 教程

1.实现线程安全的单例模式

一、第一次检查:​​避免不必要的同步(提高性能)​

  • ​目的​​:在​​大多数情况下,实例已经被创建了​​,我们​​不希望每次调用 getInstance()都进入同步块​​,因为同步(即 synchronized)是有性能开销的。

  • 如果 ​​instance 已经不为 null​​,说明单例已经创建,那么​​直接返回即可,不需进入 synchronized 块​​,避免了线程排队等待锁,提升了性能。

二、第二次检查:​​确保单例只被创建一次(线程安全

  • 进入 synchronized 块的线程可能有多个(在第一次检查都发现 instance == null 的情况下)。

  • ​第一个进入同步块的线程​​会创建实例,但​​后面其他线程可能在等待锁释放后,也进入同步块​​。

  • 如果​​没有第二次检查​​,这些线程会​​再次创建新的实例​​,导致单例模式失效。

​双重检查锁(Double-Checked Locking, DCL)​​ 实现线程安全的​​懒汉式单例模式​

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;
}
}

2.怎样自定义一个类加载器

先复习一下类加载器的关键方法:

核心方法:

  • ClassLoader.loadClass(String name)

    • 加载指定类名的类,​​默认实现遵循双亲委派机制​​。

    • 该途径内部会先委派给父类加载器,父类加载不了才自己尝试加载。

  • ClassLoader.findClass(String name)

    • ​真正去查找并定义一个类​​的方法,​​默认实现是抛出 ClassNotFoundException​​。

    • ​自定义类加载器通常重写该方法!​

  • ClassLoader.defineClass(byte[] b, int off, int len)

    • ​将字节数组(.class 材料的内容)转换为 Class 对象​​,这是 JVM 提供的一个 native 途径,​​一般由 findClass 调用​​。

步骤 1:继承 ClassLoader

通常你只需要继承 ClassLoader(或者 URLClassLoader,如果你想基于路径/URL 加载),然后​​重写 findClass(String name)方法​

步骤 2:实现 findClass方法

在这个方法中,你要求:

  1. ​根据类名,找到对应的 .class 材料(或字节码来源:文件、网络、内存、加密文件等)​

  2. ​读取该文件的字节码(byte[])​

  3. ​调用 defineClass(name, byte[], offset, length)方法,将字节数组转为 Class 对象​

3.SPI

SPI(Service Provider Interface,服务提供者接口)​​ 是 Java 提供的一种​​服务发现机制​​,它定义了一种 ​​“接口与建立相分离”​​ 的规范,允许 ​​第三方为某个接口提供具体实现​​,并在运行时​​动态地被发现和加载​​。

JDBC 是 SPI 的典型应用场景

1. JDBC 定义了一个标准接口

java.sql.Driver

这是由 ​​JDK 提供的接口​​,它定义了连接数据库的标准方法,比如 connect()

但它并没有提供具体实现,比如连接 MySQL、Oracle 的代码。

2. 各数据库厂商提供构建:

比如:

  • MySQL 提供了 com.mysql.cj.jdbc.Driver

  • Oracle 提供了 oracle.jdbc.driver.OracleDriver

这些类,就是 ​​SPI 的服务提供者实现(Service Provider)​​。

3. 但这些实现类不是由我们手动去 new 的,而是通过 ​​SPI 机制自动发现和加载的!​

关键点在于:​​MySQL 的 jar 包中有一个文件:​

​META-INF/services/java.sql.Driver

档案中就写了

com.mysql.cj.jdbc.Driver

它就告诉 JVM:“如果你想找一个 java.sql.Driver的实现,可以加载我这个类”。

​Java 在运行时通过 ServiceLoader找到这个配置,自动加载并实例化该驱动

posted @ 2025-09-19 22:45  yxysuanfa  阅读(9)  评论(0)    收藏  举报