关于使用ContextClassLoader遇到的问题

 更新时间:2023年10月07日 09:52:59   作者:sunct  
这篇文章主要介绍了关于使用ContextClassLoader遇到的问题,ContextClassLoader是通过Thread.currentThread().getContextClassLoader()返回该线程上下文的ClassLoader,需要的朋友可以参考下

关于使用ContextClassLoader遇到的问题

对ContextClassLoader有一些疑惑:

  1. 父线程加载的Class,子线程是否可以使用该Class? 答:可以
  2. 子线程加载的Class,父线程是否可以使用该Class? 答:不可以
  3. 如果一个线程加载的Class,其他线程是否可以使用该Class ? 答:不可以
  4. 怎么使用ContextClassLoader才是正确姿势呢? 答:取出->更改->还原(finally语句块)。

关于上述4点疑问,做了以下测试:

父线程加载的Class,子线程是否可以使用该Class?

/**
 * Thread.currentThread().setContextClassLoader
 * 如果父线程加载了某个class, 那么子线程也可以使用该class
 */
public class Test2 {
    public static void main(String[] args) throws InterruptedException {
        ClassLoader ccl = Thread.currentThread().getContextClassLoader();
        MyClassLoader classLoader = new MyClassLoader();
            classLoader.setClassFile(new File("D:\\UserService3Impl.class"));
            Thread.currentThread().setContextClassLoader(classLoader);
            try {
                classLoader.loadClass("com.sample.mybatis.service.impl.UserService3Impl");
            } catch (Exception e) {
                e.printStackTrace();
            }
        Thread thread = new Thread(() -> {
            try {
                Class<?> userClass = Thread.currentThread().getContextClassLoader().loadClass("com.sample.mybatis.service.impl.UserService3Impl");
                System.out.println(userClass);
                UserService3 userObj = (UserService3)userClass.newInstance();
                System.out.println(Thread.currentThread().getName() + " ==> " + userObj.getUserNo());
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
         thread.start();
    }
}

运行结果:

在这里插入图片描述

结论:父线程加载的Class,子线程是可以使用该Class

子线程加载的Class,父线程是否可以使用该Class?

/**
 * Thread.currentThread().setContextClassLoader
 * 如果子线程加载了某个class, 那么父线程不能共享到该class
 */
public class Test4 {
    public static void main(String[] args) throws Exception {
        Thread thread = new Thread(() -> {
            try {
                MyClassLoader classLoader = new MyClassLoader();
                classLoader.setClassFile(new File("D:\\UserService3Impl.class"));
                Thread.currentThread().setContextClassLoader(classLoader);
                try {
                    classLoader.loadClass("com.sample.mybatis.service.impl.UserService3Impl");
                } catch (Exception e) {
                    e.printStackTrace();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
        thread.start();
        thread.join();
        Class<?> userClass = Thread.currentThread().getContextClassLoader().loadClass("com.sample.mybatis.service.impl.UserService3Impl");
        System.out.println(userClass);
        UserService3 userObj = (UserService3) userClass.newInstance();
        System.out.println(Thread.currentThread().getName() + " ==> " + userObj.getUserNo());
    }
}

运行结果:

在这里插入图片描述

结论:子线程加载的Class,父线程是不可以使用该Class

如果一个线程加载的Class,其他线程是否可以使用该Class?

测试代码:

/**
 * 如果两个线程不是父子线程, 线程之间不会共享加载过的class
 */
public class Test3 {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(() -> {
            MyClassLoader classLoader = new MyClassLoader();
            classLoader.setClassFile(new File("D:\\UserService3Impl.class"));
            Thread.currentThread().setContextClassLoader(classLoader);
            Class<?> userClass = null;
            try {
                userClass = classLoader.loadClass("com.sample.mybatis.service.impl.UserService3Impl");
                System.out.println(userClass);
                UserService3 userObj = (UserService3) userClass.newInstance();
                System.out.println(Thread.currentThread().getName() + " ==> " + userObj.getUserNo());
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
        thread.start();
        thread.join();
        Thread thread2 = new Thread(() -> {
            try {
                Class<?> userClass = Thread.currentThread().getContextClassLoader().loadClass("com.sample.mybatis.service.impl.UserService3Impl");
                System.out.println(userClass);
                UserService3 userObj = (UserService3) userClass.newInstance();
                System.out.println(Thread.currentThread().getName() + " ==> " + userObj.getUserNo());
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
        thread2.start();
    }
}

运行结果:

在这里插入图片描述

总结:如果一个线程加载的Class,其他线程是不可以使用该Class

怎么使用ContextClassLoader才是正确姿势呢?

ClassLoader ccl = Thread.currentThread().getContextClassLoader(); //取出
try {
    MyClassLoader classLoader = new MyClassLoader();
    classLoader.setClassFile(new File("D:\\UserService3Impl.class"));
    Thread.currentThread().setContextClassLoader(classLoader); //设置
    //其他逻辑。。。
}finally {
    Thread.currentThread().setContextClassLoader(ccl); //还原
}

到此这篇关于关于使用ContextClassLoader遇到的问题的文章就介绍到这了,更多相关ContextClassLoader使用详解内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • java 从服务器下载文件并保存到本地的示例

    java 从服务器下载文件并保存到本地的示例

    本篇文章主要介绍了java 从服务器下载文件并保存到本地的示例,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-02-02
  • jedis的return行为源码解析

    jedis的return行为源码解析

    这篇文章主要为大家介绍了jedis的return行为源码解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-09-09
  • Spring maven filtering使用方法详解

    Spring maven filtering使用方法详解

    这篇文章主要介绍了Spring maven filtering使用方法详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-09-09
  • Spring,hibernate,struts经典面试笔试题(含答案)

    Spring,hibernate,struts经典面试笔试题(含答案)

    这篇文章主要介绍了Spring,hibernate,struts经典面试笔试题极其参考含答案,涉及SSH基本概念,原理与使用技巧,需要的朋友可以参考下
    2016-03-03
  • 基于java中cas实现的探索

    基于java中cas实现的探索

    这篇文章主要介绍了java中cas实现的探索,基于很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-12-12
  • SpringMVC通过模型视图ModelAndView渲染视图的实现

    SpringMVC通过模型视图ModelAndView渲染视图的实现

    这篇文章主要介绍了SpringMVC通过模型视图ModelAndView渲染视图的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-12-12
  • SpringBoot整合RabbitMQ实现交换机与队列的绑定

    SpringBoot整合RabbitMQ实现交换机与队列的绑定

    这篇文章将通过几个实例为大家介绍一些SpringBoot中RabbitMQ如何绑定交换机(交换器)与队列,文中的示例代码讲解详细,感兴趣的可以了解一下
    2022-05-05
  • idea中增强for循环提示unexpected token问题

    idea中增强for循环提示unexpected token问题

    这篇文章主要介绍了idea中增强for循环提示unexpected token问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-01-01
  • 解决idea使用maven编译正常但是运行项目时却提示很多jar包找不到的问题

    解决idea使用maven编译正常但是运行项目时却提示很多jar包找不到的问题

    这篇文章主要介绍了解决idea使用maven编译正常但是运行项目时却提示很多jar包找不到的问题,本文分多种情形给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-07-07
  • Spring Get请求与post请求的实现

    Spring Get请求与post请求的实现

    在Spring中,GET请求和POST请求是两种常见的HTTP请求方法,用于与服务器进行交互,本文详细的介绍一下Spring Get请求与post请求的实现,感兴趣的可以了解一下
    2023-10-10

最新评论