关于使用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使用详解内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • idea没有services窗口、没有springboot启动项问题

    idea没有services窗口、没有springboot启动项问题

    这篇文章主要介绍了idea没有services窗口、没有springboot启动项问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-05-05
  • Java面试题冲刺第十五天--设计模式

    Java面试题冲刺第十五天--设计模式

    这篇文章主要为大家分享了最有价值的三道关于设计模式的面试题,涵盖内容全面,包括数据结构和算法相关的题目、经典面试编程题等,感兴趣的小伙伴们可以参考一下
    2021-08-08
  • JAVA利用接口实现多继承问题的代码实操演示

    JAVA利用接口实现多继承问题的代码实操演示

    Java语言并不支持多继承,这是由于多继承会带来许多复杂的问题,例如"菱形问题"等,下面这篇文章主要给大家介绍了关于JAVA利用接口实现多继承问题的相关资料,需要的朋友可以参考下
    2024-03-03
  • 一文搞懂Java中的序列化与反序列化

    一文搞懂Java中的序列化与反序列化

    序列化是将对象转换成二进制字节流的过程;反序列化是从二进制字节流中恢复对象的过程。文中降通过示例详解二者的使用与区别,需要的可以参考一下
    2022-08-08
  • SpringBoot实现邮件推送的详细代码

    SpringBoot实现邮件推送的详细代码

    在项目中经常会遇到SpringBoot推送消息的业务,除了站内推送通知,邮件推送也是一种常见的方式,本文小编就带大家实现邮件推送,文中有详细代码讲解,对大家的学习或工作有一定的帮助,需要的朋友可以参考下
    2024-04-04
  • PostMan传@RequestParam修饰的数组方式

    PostMan传@RequestParam修饰的数组方式

    这篇文章主要介绍了PostMan传@RequestParam修饰的数组方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-08-08
  • Java基础巩固小项目点菜系统的实现

    Java基础巩固小项目点菜系统的实现

    这篇文章主要介绍了一个Java小项目点菜系统的实现,主要是用的集合,适合正在学习Java的朋友拿来实战练手,感兴趣的朋友快来看看吧
    2022-03-03
  • Java如何实现List自定义排序

    Java如何实现List自定义排序

    这篇文章主要介绍了Java如何实现List自定义排序,帮助大家更好的理解和使用Java,感兴趣的朋友可以了解下
    2020-09-09
  • Java Ehcache缓存框架入门级使用实例

    Java Ehcache缓存框架入门级使用实例

    这篇文章主要介绍了Java Ehcache缓存框架入门级使用实例,具有一定的参考价值,感兴趣的小伙伴们可以参考一下。
    2017-08-08
  • Java如何基于DOM解析xml文件

    Java如何基于DOM解析xml文件

    这篇文章主要介绍了Java如何基于DOM解析xml文件,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-09-09

最新评论