【面试题精讲】JVM-打破双亲委派机制-线程上下文类加载器

简介: 【面试题精讲】JVM-打破双亲委派机制-线程上下文类加载器

1. 什么是线程上下文类加载器?

线程上下文类加载器(Thread Context ClassLoader)简称 TCCL,是 Java 中一个重要的概念,它是 Java 中的一个类加载器,用于加载线程上下文中所需要的类。其本质上是一个普通的 Java 类,不同之处在于其拓展了 ClassLoader 基础类,提供了一些特殊的功能。线程上下文类加载器和普通类加载器不同的是,它不需要遵循双亲委派机制。

2. 为什么需要线程上下文类加载器?

Java 应用程序中,类的加载是由类加载器完成的,按照双亲委派机制的规则,子类加载器会向父级类加载器请求加载,如果父级类加载器不能完成加载操作,则会将其沿上继续传递给更高级别的父级类加载器,最终如果找不到对应类加载器,则系统将会抛出 ClassNotFoundException 异常。双亲委派机制一方面可以保证 Java 平台核心类的安全性,另一方面也可以保证 Java 核心类库的稳定性和正确性。

但是,有时候我们希望某些类的加载不受双亲委派机制的限制,比如一些框架或者插件就需要自己实现一套类加载机制。这时候就需要线程上下文类加载器来打破双亲委派机制,使得父类加载器可以访问到子类加载器加载的类。

3. 线程上下文类加载器的实现原理

线程上下文类加载器代码实现非常简单,它的主要思想是在需要访问的类的加载器不同的时候,通过线程上下文类加载器来进行操作。

public class Demo {
    public static void main(String[] args) {
        ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();
        Thread.currentThread().setContextClassLoader(new MyClassLoader());
        // 执行操作
        Thread.currentThread().setContextClassLoader(oldClassLoader);
    }
}

在上面的代码中,我们首先获取了当前线程的上下文类加载器,然后将其重新设置成自定义的 MyClassLoader,执行一些需要访问不同类加载器的操作,最后需要将当前线程的上下文类加载器重新设置为原来的类加载器。

4. 线程上下文类加载器的使用示例

Java 中经典的线程上下文类加载器的案例就是 JDBC 规范。JDBC 规范中定义了一系列接口,这些接口通常由驱动程序提供实现。当 JDBC 的客户端在应用程序中加载驱动程序时,驱动程序的类加载器加载了具体的类,不同的数据库的驱动程序类在不同的类加载器中。

这样就可能出现了两种情况:

  1. 当前线程的类加载器为驱动程序类加载器,但是应用程序获取的数据库连接是由另一个类加载器加载的。
  2. 当前线程的类加载器为应用程序类加载器,但是驱动程序获取的数据库连接是由另一个类加载器加载的。

以上两种情况都会造成 ClassNotFoundException 异常。所以为了解决这种情况,JDBC 规范使用了线程上下文类加载器。

5. 线程上下文类加载器的优点

线程上下文类加载器解决了类加载机制中父子类加载器的限制,可以在不破坏双亲委派模型的基础上,允许线程在运行期间使用自己的加载器读取类库。

另外,线程上下文类加载器还可以增加程序的灵活性,在不同的容器中运行程序时,可以使用其特有的类加载器,加载不同环境需要的类,可以解决常见的 jar 冲突问题。

6. 线程上下文类加载器的缺点

线程上下文类加载器机制存在的问题主要是使用不当时降低性能的问题。如果不在必要的时候使用线程上下文类加载器,在获取类的时候会增大时间开销,因为是通过反射对类进行初始化的,这个操作需要一定的时间。

7. 线程上下文类加载器的使用注意事项

在线程中使用线程上下文类加载器时,需要注意以下几点:

  1. 在线程的运行期间,可以使用 setContextClassLoader()方法来设置线程上下文类加载器,线程结束后需要将其还原到原始类加载器,以免影响其他线程的正常运行。
  2. 如果在应用程序中使用自定义的类加载器,需要一些特殊的代码来隔离各个加载器。 在容器框架中,通常不需要直接操作线程上下文类加载器,而是使用如 Java 2 Platform Standard Edition(Edition)1.3.1 或更高版本中提供的 Thread.currentThread().getContextClassLoader()方法,将线程的上下文类加载器设置为当前线程的类加载器。

8. 总结

线程上下文类加载器是 Java 虚拟机提供的一个重要概念。其本质是一个 Java 类,用于加载线程上下文中所需要的类。它的作用是为了打破双亲委派机制,在某些情况下需要读取特定的类库或者线程需要使用特定的类库时,可以通过线程上下文类加载器实现。线程上下文类加载器有一些优点,比如可以对于同一份代码实现多次加载,以及解决不同类加载器的冲突等。但是,它也存在一些缺点,比如降低性能的问题。在使用线程上下文类加载器时,需要注意保存原始类加载器,并在合适的时候还原。同时,需要特别注意多个类加载器可能会导致冲突等问题,需要特别处理。

本文由 mdnice 多平台发布


相关文章
|
3天前
|
监控 安全 Java
【多线程学习】深入探究阻塞队列与生产者消费者模型和线程池常见面试题
【多线程学习】深入探究阻塞队列与生产者消费者模型和线程池常见面试题
|
8天前
|
Java 调度
Java面试必考题之线程的生命周期,结合源码,透彻讲解!
Java面试必考题之线程的生命周期,结合源码,透彻讲解!
38 1
|
8天前
|
Java
面试官让说出8种创建线程的方式,我只说了4种,然后挂了。。。
面试官让说出8种创建线程的方式,我只说了4种,然后挂了。。。
9 1
|
15天前
|
调度 Python
Python多线程、多进程与协程面试题解析
【4月更文挑战第14天】Python并发编程涉及多线程、多进程和协程。面试中,对这些概念的理解和应用是评估候选人的重要标准。本文介绍了它们的基础知识、常见问题和应对策略。多线程在同一进程中并发执行,多进程通过进程间通信实现并发,协程则使用`asyncio`进行轻量级线程控制。面试常遇到的问题包括并发并行混淆、GIL影响多线程性能、进程间通信不当和协程异步IO理解不清。要掌握并发模型,需明确其适用场景,理解GIL、进程间通信和协程调度机制。
30 0
|
16天前
|
监控 Java 关系型数据库
JVM工作原理与实战(十三):打破双亲委派机制-线程上下文类加载器
JVM作为Java程序的运行环境,其负责解释和执行字节码,管理内存,确保安全,支持多线程和提供性能监控工具,以及确保程序的跨平台运行。本文主要介绍了打破双亲委派机制的方法、线程上下文类加载器等内容。
15 2
|
20天前
|
存储 安全 Java
多线程编程常见面试题讲解(锁策略,CAS策略,synchronized原理,JUC组件,集合类)(下)
多线程编程常见面试题讲解(锁策略,CAS策略,synchronized原理,JUC组件,集合类)(下)
43 0
|
20天前
|
存储 安全 Java
多线程编程常见面试题讲解(锁策略,CAS策略,synchronized原理,JUC组件,集合类)(上)
多线程编程常见面试题讲解(锁策略,CAS策略,synchronized原理,JUC组件,集合类)
35 0
|
23天前
|
缓存 算法 安全
java多线程面试题
java多线程面试题
|
3天前
|
缓存 安全 Java
多线程--深入探究多线程的重点,难点以及常考点线程安全问题
多线程--深入探究多线程的重点,难点以及常考点线程安全问题
|
3天前
|
数据采集 安全 Java
Python的多线程,守护线程,线程安全
Python的多线程,守护线程,线程安全