【面试题精讲】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 多平台发布


相关文章
|
1月前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
77 2
|
3天前
|
并行计算 算法 安全
面试必问的多线程优化技巧与实战
多线程编程是现代软件开发中不可或缺的一部分,特别是在处理高并发场景和优化程序性能时。作为Java开发者,掌握多线程优化技巧不仅能够提升程序的执行效率,还能在面试中脱颖而出。本文将从多线程基础、线程与进程的区别、多线程的优势出发,深入探讨如何避免死锁与竞态条件、线程间的通信机制、线程池的使用优势、线程优化算法与数据结构的选择,以及硬件加速技术。通过多个Java示例,我们将揭示这些技术的底层原理与实现方法。
41 3
|
1月前
|
SQL 缓存 监控
大厂面试高频:4 大性能优化策略(数据库、SQL、JVM等)
本文详细解析了数据库、缓存、异步处理和Web性能优化四大策略,系统性能优化必知必备,大厂面试高频。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
大厂面试高频:4 大性能优化策略(数据库、SQL、JVM等)
|
1月前
|
存储 缓存 算法
面试官:单核 CPU 支持 Java 多线程吗?为什么?被问懵了!
本文介绍了多线程环境下的几个关键概念,包括时间片、超线程、上下文切换及其影响因素,以及线程调度的两种方式——抢占式调度和协同式调度。文章还讨论了减少上下文切换次数以提高多线程程序效率的方法,如无锁并发编程、使用CAS算法等,并提出了合理的线程数量配置策略,以平衡CPU利用率和线程切换开销。
面试官:单核 CPU 支持 Java 多线程吗?为什么?被问懵了!
|
2天前
|
缓存 安全 Java
【JavaEE】——单例模式引起的多线程安全问题:“饿汉/懒汉”模式,及解决思路和方法(面试高频)
单例模式下,“饿汉模式”,“懒汉模式”,单例模式下引起的线程安全问题,解锁思路和解决方法
|
2天前
|
Java 调度
|
3月前
|
安全 Java 应用服务中间件
JVM常见面试题(三):类加载器,双亲委派模型,类装载的执行过程
什么是类加载器,类加载器有哪些;什么是双亲委派模型,JVM为什么采用双亲委派机制,打破双亲委派机制;类装载的执行过程
108 35
JVM常见面试题(三):类加载器,双亲委派模型,类装载的执行过程
|
2月前
|
存储 监控 算法
美团面试:说说 G1垃圾回收 底层原理?说说你 JVM 调优的过程 ?
尼恩提示: G1垃圾回收 原理非常重要, 是面试的重点, 大家一定要好好掌握
美团面试:说说 G1垃圾回收 底层原理?说说你 JVM 调优的过程  ?
|
2月前
|
消息中间件 存储 Java
Android面试高频知识点(2) 详解Android消息处理机制(Handler)
Android面试高频知识点(2) 详解Android消息处理机制(Handler)
|
2月前
|
消息中间件 存储 Java
Android面试高频知识点(2) 详解Android消息处理机制(Handler)
Android面试高频知识点(2) 详解Android消息处理机制(Handler)
61 1