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

相关文章

  • springboot连接kafka集群的使用示例

    springboot连接kafka集群的使用示例

    在项目中使用kafka的场景有很多,尤其是实时产生的数据流,本文主要介绍了springboot连接kafka集群的使用示例,具有一定的参考价值,感兴趣的可以了解一下
    2023-09-09
  • Mybatis基于MapperScan注解的动态代理加载机制详解

    Mybatis基于MapperScan注解的动态代理加载机制详解

    这篇文章主要介绍了Mybatis基于MapperScan注解的动态代理加载机制,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习吧
    2023-01-01
  • 关于Spring启动时Context加载源码分析

    关于Spring启动时Context加载源码分析

    这篇文章通过源码分析主要给大家介绍了关于Spring启动时Context加载的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧。
    2018-01-01
  • Java使用jmeter进行压力测试

    Java使用jmeter进行压力测试

    本篇文章简单讲一下使用jmeter进行压力测试。其压测思想就是 通过创建指定数量的线程,同时请求指定接口,来模拟指定数量用户同时进行某个操作的场景,感兴趣的小伙伴们可以参考一下
    2021-07-07
  • java获取各种路径的基本方法

    java获取各种路径的基本方法

    这篇文章主要为大家详细介绍了java获取各种路径的基本方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-10-10
  • springboot读取自定义配置文件节点的方法

    springboot读取自定义配置文件节点的方法

    这篇文章主要介绍了springboot读取自定义配置文件节点的方法,本文给大家介绍的非常不错,具有一定的参考借鉴价值 ,需要的朋友可以参考下
    2018-05-05
  • JAVA各种加密与解密方式总结大全

    JAVA各种加密与解密方式总结大全

    这篇文章主要给大家介绍了关于JAVA各种加密与解密方式总结的相关资料,加密是指对原来为明文的文件或数据按某种算法进行处理,使其成为不可读的一段代码,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2023-07-07
  • springmvc HttpServletRequest 如何获取c:forEach的值

    springmvc HttpServletRequest 如何获取c:forEach的值

    这篇文章主要介绍了springmvc HttpServletRequest 如何获取c:forEach的值方法,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-08-08
  • java启动jar包设置启动参数的实现

    java启动jar包设置启动参数的实现

    本文主要介绍了java启动jar包设置启动参数的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-06-06
  • Jackson多态序列化图文详解

    Jackson多态序列化图文详解

    jackson允许配置多态类型处理,当进行反序列话时,JSON数据匹配的对象可能有多个子类型,为了正确的读取对象的类型,我们需要添加一些类型信息,下面这篇文章主要给大家介绍了关于Jackson多态序列化的相关资料,需要的朋友可以参考下
    2022-06-06

最新评论