重置线程中断状态_记住要重置线程上下文类加载器

重置线程中断状态

我很难思考与Java 加载有关的东西,而不是与类加载器有关的东西。 在使用应用程序服务器或OSGi的情况下尤其如此,在这些应用程序服务器或OSGi中,经常使用多个类加载器,并且透明地使用类加载器的能力降低。 我同意OSGI Alliance Blog文章中关于类加载器的知识 ,“在模块化环境中,类加载器代码会造成严重破坏。”

Neil Bartlett在博客文章The Dreaded Thread Context Class Loader上发表了文章,他在文章中介绍了为什么引入了线程上下文类加载器以及为什么它的使用对OSGi不友好。 Bartlett指出,在极少数情况下,“一个库只咨询TCCL”,但在极少数情况下,“我们被困住了”,并且“在调用该库之前,必须从我们自己的代码中显式设置TCCL。”

Alex Miller也撰写了有关线程上下文类加载器 (TCCL)的文章,并指出“ Java框架没有遵循一致的类加载模式”,并且“许多常见且重要的框架的确使用了线程上下文类加载器(JMX,JAXP, JNDI ,等等)。” 他强调了这一点,“如果您使用的是J2EE应用服务器,则几乎可以肯定,您依赖于使用线程上下文类加载器的代码。” 在那篇文章中 ,Miller提供了一种基于动态代理的解决方案,以在需要“设置线程上下文类加载器”然后“记住原始上下文类加载器并重新设置”的情况下提供帮助。

Knopflerfish Framework (一种OSGi实现)在其文档的“编程”部分中描述了如何使用线程上下文类加载器。 以下引用摘录自Knopflerfish 5.2的“编程”文档的“设置上下文类加载器”部分:


像大多数JNDI查找服务一样,许多外部库都需要正确设置
线程上下文类加载器 如果未设置,则即使包含了所有必需的库,也可能引发ClassNotFoundException或类似事件。 要解决此问题,只需在激活器中生成一个新线程并从该线程中进行工作即可。 … 它是
建议在启动线程上永久设置上下文类加载器,因为该线程对于您的捆绑包可能不是唯一的。 效果可能因OSGi供应商而异。 如果您不生成新线程,则您
返回之前必须重置上下文类加载器。

Knopflerish提供了一个简单的类org.knopflerfish.util.ClassLoaderUtil ,它支持切换到提供的类加载器(在OSGi应用程序中可能经常是线程上下文类加载器),并通过finally子句确保重置了原始上下文类加载器。操作完成后。 我已经实现了该类的我自己的改编,该改编在下一个代码清单中显示。

ClassLoaderSwitcher.java

package dustin.examples.classloader;/*** Utility class for running operations on an explicitly specified class loader.*/
public class ClassLoaderSwitcher
{/*** Execute the specified action on the provided class loader.** @param classLoaderToSwitchTo Class loader from which the*    provided action should be executed.* @param actionToPerformOnProvidedClassLoader Action to be*    performed on the provided class loader.* @param <T> Type of Object returned by specified action method.* @return Object returned by the specified action method.*/public static <T> T executeActionOnSpecifiedClassLoader(final ClassLoader classLoaderToSwitchTo,final ExecutableAction<T> actionToPerformOnProvidedClassLoader){final ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader();try{Thread.currentThread().setContextClassLoader(classLoaderToSwitchTo);return actionToPerformOnProvidedClassLoader.run();}finally{Thread.currentThread().setContextClassLoader(originalClassLoader);}}/*** Execute the specified action on the provided class loader.** @param classLoaderToSwitchTo Class loader from which the*    provided action should be executed.* @param actionToPerformOnProvidedClassLoader Action to be*    performed on the provided class loader.* @param <T> Type of Object returned by specified action method.* @return Object returned by the specified action method.* @throws Exception Exception that might be thrown by the*    specified action.*/public static <T> T executeActionOnSpecifiedClassLoader(final ClassLoader classLoaderToSwitchTo,final ExecutableExceptionableAction<T> actionToPerformOnProvidedClassLoader) throws Exception{final ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader();try{Thread.currentThread().setContextClassLoader(classLoaderToSwitchTo);return actionToPerformOnProvidedClassLoader.run();}finally{Thread.currentThread().setContextClassLoader(originalClassLoader);}}
}

ClassLoaderSwitcher类上定义的两个方法每个都将接口作为其参数之一,并带有指定的类加载器。 接口使用run()方法指定一个对象,并且将针对提供的类加载器执行run()方法。 接下来的两个代码清单显示接口ExecutableActionExecutableExceptionableAction

ExecutableAction.java

package dustin.examples.classloader;/*** Encapsulates action to be executed.*/
public interface ExecutableAction<T>
{/*** Execute the operation.** @return Optional value returned by this operation;*    implementations should document what, if anything,*    is returned by implementations of this method.*/T run();
}

ExecutableExceptionableAction.java

package dustin.examples.classloader;/*** Describes action to be executed that is declared* to throw a checked exception.*/
public interface ExecutableExceptionableAction<T>
{/*** Execute the operation.** @return Optional value returned by this operation;*    implementations should document what, if anything,*    is returned by implementations of this method.* @throws Exception that might be possibly thrown by this*    operation.*/T run() throws Exception;
}

客户端调用ClassLoaderSwitcher类上定义的方法的代码行不一定比它们自己进行临时上下文类加载器切换时要少,但是使用这样的通用类可以确保始终更改上下文类加载器返回到原始类加载器,从而消除了开发人员确保可进行重置的需求,并防止了“重置”在某个时候被无意中删除或在过程中的某个时候移得太晚了。

需要为操作临时更改上下文类加载器的客户端可能会这样做,如下所示:

临时直接将ClassLoader切换为执行动作

final ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader();
try
{Thread.currentThread().setContextClassLoader(BundleActivator.class.getClassLoader());final String returnedClassLoaderString =String.valueOf(Thread.currentThread().getContextClassLoader())
}
finally
{Thread.currentThread().setContextClassLoader(originalClassLoader);
}

没有太多的代码行,但是必须记住要将上下文类加载器重置为其原始类加载器。 接下来演示如何使用ClassLoaderSwitcher实用工具类执行相同的操作。

使用ClassLoaderSwitcher切换类加载器以执行操作(JDK 8之前的版本)

final String returnedClassLoaderString = ClassLoaderSwitcher.executeActionOnSpecifiedClassLoader(BundleActivator.class.getClassLoader(),new ExecutableAction<String>(){@Overridepublic String run(){return String.valueOf(Thread.currentThread().getContextClassLoader());}});

最后一个例子并不比第一个例子短,但是开发人员无需担心在第二个例子中显式地重置上下文类加载器。 请注意,这两个示例引用BundleActivator来在OSGi应用程序中获取Activator / System类加载器。 这是我在这里使用的,但是可以在此处使用任何在适当的类加载器上加载的类,而不是BundleActivator 。 需要注意的另一件事是,我的示例使用了一个非常简单的操作,该操作在指定的类加载器上执行(返回当前线程上下文类加载器的String表示形式),在这里效果很好,因为它使我很容易看到指定的类加载器是用过的。 在实际情况下,此方法可以是在指定的类加载器上运行所需的任何方法。

如果我在指定的类加载器上调用的方法引发检查异常,则可以使用ClassLoaderSwitcher提供的另一个重载方法(同名)来运行该方法。 下一个代码清单中对此进行了演示。

将ClassLoaderSwitcher与可能引发检查异常的方法一起使用(JDK 8之前的版本)

String returnedClassLoaderString = null;
try
{returnedClassLoaderString = ClassLoaderSwitcher.executeActionOnSpecifiedClassLoader(BundleActivator.class.getClassLoader(),new ExecutableExceptionableAction<String>(){@Overridepublic String run() throws Exception{return mightThrowException();}});
}
catch (Exception exception)
{System.out.println("Exception thrown while trying to run action.");
}

使用JDK 8,我们可以使客户端代码更加简洁。 接下来的两个代码清单包含与前面两个代码清单中显示的方法相对应的方法,但已更改为JDK 8样式。

使用ClassLoaderSwitcher切换类加载器以执行动作(JDK 8样式)

final String returnedClassLoaderString = ClassLoaderSwitcher.executeActionOnSpecifiedClassLoader(urlClassLoader,(ExecutableAction<String>) () ->{return String.valueOf(Thread.currentThread().getContextClassLoader());});

将ClassLoaderSwitcher与可能引发检查异常的方法一起使用(JDK 8样式)

String returnedClassLoaderString = null;
try
{returnedClassLoaderString = ClassLoaderSwitcher.executeActionOnSpecifiedClassLoader(urlClassLoader,(ExecutableExceptionableAction<String>) () -> {return mightThrowException();});
}
catch (Exception exception)
{System.out.println("Exception thrown while trying to run action.");
}

与直接设置和重置上下文类加载器相比, JDK 8的lambda表达式使使用ClassLoaderSwitcher的客户端代码更简洁(并且可以说更具可读性),同时通过确保始终将上下文类加载器切换回其来提供更高的安全性。原始类加载器。

结论

尽管无疑最好避免尽可能多地切换上下文类加载器,但是有时您可能没有其他合理的选择。 在那些时候,将开关中涉及的多个步骤封装起来,然后再切换回一个可以由客户端调用的方法,这可以增加操作的安全性,并且如果使用JDK 8编写,甚至可以使客户端拥有更简洁的代码。

其他参考

在本文中已经提到了其中一些参考,甚至对其进行了重点介绍,但为方便起见,在此再次将其包括在内。

  • GitHub上用于此博客文章中完整类的源代码 (不同的包名称)
  • OSGi联盟: 关于类加载器的知识
  • Neil Bartlett: 可怕的线程上下文类加载器
  • 纯粹的危险: 两个类加载器的故事
  • 信息矿山: OSGi类加载
  • JNDI教程:类加载
  • Adobe:OSGi中的类加载器问题 使用Thread上下文的第三方库
  • 揭秘Java类加载
  • Knopflerfish 5.2.0文档: 编程Knopflerfish:设置上下文类加载器
  • Knopflerfish 5.2.0 Javadoc: org.knopflerfish.util.ClassLoaderUtil
  • JavaWorld: 从ClassLoader迷宫中寻找出路
  • 技术与达尔文尼亚: Java ClassLoader和Context ClassLoader
  • Impala博客: 在多模块环境中使用线程的上下文类加载器

翻译自: https://www.javacodegeeks.com/2016/08/remembering-reset-thread-context-class-loader.html

重置线程中断状态

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/335711.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【WebRTC---源码篇】(十一)WebRTC编码与发送H264持续更新中

H264在WebRTC中是如何编解码的? h264编解码代码位于文件src\modules\video_coding\codecs\h264下 #ifndef MODULES_VIDEO_CODING_CODECS_H264_INCLUDE_H264_H_ #define MODULES_VIDEO_CODING_CODECS_H264_INCLUDE_H264_H_#include <memory> #include <vector>#i…

python大一题库西农_生态学(西北农林科技大学)知到智慧树2020章节测试答案...

生态学(西北农林科技大学)知到智慧树2020章节测试答案更多相关问题【单选题】在测定食品中灰分含量时,灼烧残留物不可能存在的是( )A. 蔗糖 B. 钠 C. 钾 D. 氯【单选题】对于老年骨质疏松说法错误的是( )A. 老年骨质疏松症属于继发性骨质疏松症 B. 是使骨质脆性增加导致骨折危险…

EL表达式学习笔记

文章目录EL 表达式是干什么用的EL 表达式的底层原理EL 表达式可以用在哪些地方EL 表达式用来访问 JavaBean 的属性EL 表达式获取请求参数的值EL 表达式用于运算&#xff0c;将结果作为标签的属性值或者直接输出Struts2 的 EL 表达式EL 表达式翻译为 Java 代码的含义EL 表达式示…

【WebRTC---源码篇】(十二)WebRTC/RTX协议

在SDP中可以查询到提前协商好的RTX信息 接受到RTCP NACK 重传RTX包,有效荷载前两个字节为原始seqnumber 如何知道重传的是哪个包 发送RTX

stackoverflow_Stackoverflow:您尚未发现的7个最佳Java答案

stackoverflow您可以在Stackoverflow上找到哪些最有趣的答案&#xff1f; Stackoverflow是开发人员的金矿。 它可以帮助我们找到遇到的特定问题的最有用答案&#xff0c;并且我们总是从中学习新事物。 在以下文章中&#xff0c;我们研究了最受欢迎的Java问题和答案&#xff0…

json请求 post vue_Spring Boot+Vueaxios异步请求数据的12种操作(上篇)

Java大联盟致力于最高效的Java学习关注Spring Boot Vue 前后端分离最核心的操作就是通过异步请求完成数据同步&#xff0c;这其中又可以分为很多种不同的情况&#xff0c;比如是 GET 请求还是 POST 请求&#xff1f;参数是普通变量还是 JSON&#xff1f;基于 RESTful 架构如何…

数据库SQL语言分类(DDL/DML/DQL/TCL/DCL)

文章目录一、数据定义语言 DDL&#xff08;一&#xff09;create 数据库对象的创建&#xff08;二&#xff09;alter 修改数据库对象&#xff08;三&#xff09;drop 删除数据库对象&#xff08;四&#xff09;truncate 清空表数据二、数据操纵语言 DML&#xff08;一&#xff…

【WebRTC---源码篇】(十三)WebRTC/Pacer

pacer作用 NextSendTime Timestamp PacingController::NextSendTime() const {Timestamp now = CurrentTime();if (paused_) {return last_send_time_ + kPausedProcessInterval;}// If probing is active, that always takes priority.if (prober_.IsProbing()) {Timest…

卡夫卡如何分区_通过分区在卡夫卡实现订单担保人

卡夫卡如何分区Kafka最重要的功能之一是实现消息的负载平衡&#xff0c;并保证分布式集群中的排序&#xff0c;否则在传统队列中是不可能的。 首先让我们尝试了解问题陈述 让我们假设我们有一个主题&#xff0c;其中发送消息&#xff0c;并且有一个消费者正在使用这些消息。 …

全景视觉空间直线检测_视觉SLAM深度解读

近年来&#xff0c;SLAM技术取得了惊人的发展&#xff0c;领先一步的激光SLAM已成熟的应用于各大场景中&#xff0c;视觉SLAM虽在落地应用上不及激光SLAM&#xff0c;但也是目前研究的一大热点&#xff0c;今天我们就来详细聊聊视觉SLAM的那些事儿。视觉SLAM是什么&#xff1f;…

HTTP网页请求响应的状态码/状态代码

文章目录1开头 询问客户端是否还有请求消息2开头 &#xff08;请求成功&#xff09;表示成功处理了请求的状态代码3开头 &#xff08;请求被重定向&#xff09;表示要完成请求&#xff0c;需要进一步操作。 通常&#xff0c;这些状态代码用来重定向4开头 &#xff08;请求错误&…

某人想在h小时内钓到_为某人命名以重新连接到您的服务器

某人想在h小时内钓到在进行测试自动化时&#xff0c;通常需要知道当前计算机的名称&#xff0c;以提示另一台计算机连接到它&#xff0c;特别是在并行运行测试的情况下。 本周&#xff0c;我试图对服务器进行测试&#xff0c;以使其连接回在从属测试计算机上运行的WireMock服务…

对象必须实现 iconvertible。_java面向对象最全入门笔记(通俗易懂,适合初学者)...

前言:面向对象的三大特征封装 (Encapsulation)继承 (Inheritance)多态 (Polymorphism)编程思想&#xff1a;面向过程&#xff1a;做某件事情都需要自己亲历亲为&#xff0c;按照步骤去完成面向对象&#xff1a;做某件事情不需要自己亲历亲为&#xff0c;只需指定特定的对象去完…

C++ 【随想录】(一)模拟矩阵相乘

#include<iostream> using namespace std; const int N 105; int R1[N][N], R2[N][N], ans[N][N];int main() {int m, p, n;cin >> m >> p >> n;for (int i 0; i < m; i) {//录入第一个矩阵for (int j 0; j < p; j) {cin >> R1[i][j];}…

HH SaaS电商系统的结算系统设计

文章目录一、第三方卖家销售货款结算流程说明&#xff1a;销售货款结算逻辑流程图预期收入如何统计二、第三方卖家推广分销佣金结算佣金结算逻辑流程图逾期佣金收入如何统计三、采购货款结算租户采购货款结算流程说明商城采购货款结算流程说明店铺商家的采购货款结算流程说明四…

java8并行流_Java 8:CompletableFuture与并行流

java8并行流这篇文章展示了Java 8的CompletableFuture在执行异步计算时如何与并行流进行比较。 我们将使用以下类对长时间运行的任务进行建模&#xff1a; class MyTask {private final int duration;public MyTask(int duration) {this.duration duration;}public int calc…

postgresql删除索引_PostgreSQL 13 发布,索引和查找有重大改进

9月24日&#xff0c;PostgreSQL全球开发组宣布PostgreSQL 13正式发布&#xff0c;作为世界上使用最多的开源数据库之一&#xff0c;PostgresSQL 13是目前的最新版本。PostgreSQL 13 在索引和查找方面进行了重大改进&#xff0c;有利于大型数据库系统&#xff0c;改进包括索引的…

【WebRTC---源码篇】(十六)WebRTC/NetEQ

WebRTC【4096版本】 NetEQ的作用 进行抖动控制和丢包隐藏,通过该技术可以让音频更平滑 NetEQ插入packet数据 int NetEqImpl::InsertPacketInternal(const RTPHeader& rtp_header,rtc::ArrayView<const uint8_t> payload) {//如果有效荷载payload为空if (paylo…

HH SaaS电商系统的销售订单设计

文章目录订单销售类型订单优惠优惠方式子订单优惠金额订单拆单订单发货销售订单拆单逻辑图销售订单的信息结构相关实体订单运营类型&#xff08;作废&#xff09;售后截止时间订单状态状态机的设计不同属性组合下的订单状态组合1&#xff1a;实物线上非预售非定制非拼单快递组合…

kafka netty_惠而浦:使用Netty和Kafka的微服务

kafka netty介绍 在上一个博客中 &#xff0c;我介绍了Netty用作Web服务器。 该示例运行良好……只要需要广播服务器即可。 大多数情况下不是很有用。 更有可能的是&#xff0c;每个客户端仅接收针对其的数据&#xff0c;并保留了特殊情况下的广播&#xff0c;例如“服务器在1…