不容忽视的ClassNotFoundException

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了不容忽视的ClassNotFoundException相关的知识,希望对你有一定的参考价值。

参考技术A 相信很多Java开发人员都对这个常见却不招人待见的java.lang.ClassNotFoundException并不陌生。出现这个异常的原因大家都清楚(classpath路径下缺少class文件或者jar包了,或者是类加载器委派的问题等),不过对于它给JVM带来的性能影响可能就不了解了。这个异常可能会严重影响应用程序的响应时间和可伸缩性。

大型的J2EE企业级应用,可能会同时部署有多个应用,由于同时运行着多个类加载器,就很容易导致这类问题。除非发现有业务确实受到影响或者日志监控比较详细,否则很有可能出现了ClassNotFoundException你也不知道,这导致的结果是:JVM类加载的IO开销和线程间的锁竞争给系统带来的性能问题。

本文及文中的示例程序将会告诉你,应当谨慎对待生产系统中出现的ClassNotFoundException异常,并正确的解决它。

想要正确理解这个性能问题,首先你得明白Java类加载模型的机制。ClassNotFoundException意味着JVM无法找到或者加载某个Java类:

Class.forName()方法
ClassLoader.findSysteClass()方法
ClassLoader.loadClass()方法

尽管在JVM的生命周期内,你的应用程序里面的Java类应该只会加载一次,但有些应用可能会依赖于动态的类加载机制。

不管怎么说,不停地加载失败总是很影响性能的,尤其是JDK中默认的java.lang.ClassLoader进行加载的时候。事实上,1.7以上版本的JDK,为了向下兼容,同一个类不能同时被加载,除非这个类加载器被标记为“支持并发”的。你要时刻牢记,同步操作是在类这一级实现的,由于多个Java线程并发地加载,同一个类不停的加载失败会引发线程间的锁竞争。如果是JDK1.6以前则情况更糟糕,因为同步操作是在类加载器这一层完成的。

由于这个原因,像JBoss WildFly8等JavaEE容器都使用了它们内部的并发类加载器来完成应用程序的类加载。这些类加载器都在更细粒度上进行加锁,这样同一个类加载器的实例可以同时加载多个不同的类。这和JDK1.7的优化不谋而和,它支持的并发的自定义类加载器也是防止类加载器出现死锁的现象。

不过,像java.*的系统级别的类,它们的加载还是会由JDK默认的类加载器来完成。这意味着连续的类加载失败还是可能会引发严重的线程锁竞争。这也正是本文接下来要重现并演示的场景。

为了重现并模拟这个问题,我们按照以下的规范写了一个简单的程序:

一个JAX-RS WEB服务执行Class.forName()来加载一个系统包下不存在的类:

JRE: HotSpot JDK 1.7 64位
Java EE容器:JBoss WildFly8
压测工具:Apache JMeter
Java监控工具:JVisualVM
Java故障分析:JVM Thread Dump

JAX-RS服务同时有20个线程在并发的执行。每一次调用都会触发一个ClassNotFoundException。为了减少IO的影响,日志也完全关闭了,我们只关注类加载的竞争冲突。

现在我们来看下JVisualVM在半分钟到一分钟内的监测结果。可以很明显的看到,很多线程都阻塞住了,在等待获取一个对象锁。

分析JVM的threaddump很容易就能定位出问题:线程锁竞争。从运行栈的跟踪信息可以看到,JBoss把类加载的任务委派给了JDK的类加载器。为什么?这是因为这个不存在的java类被认为是属于系统类路径底下,因此JBoss会把它的加载委派给系统的类加载器。这样因为这个类触发了系统级的同步,其它线程只能等待获取锁才能加载它。

很多线程都在等待获取0x00000000ab84c0c8的锁:

这个线程是罪魁祸首——default task 20

现在我们把要加载类的名字更换到应用程序的包下面并重新运行这段程序。

可以看到,不再有阻塞的线程出现了。为什么?我们来看下JVM的thread dump来更好的理解下为什么会出现这个变化。

由于类名不再认为属于Java系统包下,不会发生类加载委派,也就没有同步操作。
由于JBoss认为JDK1.7是一个”安全“的JDK,它会使用ConcurrentClassLoader.performLoadClassUnchecked()方法,也就不会触发对象监视器锁。
没有同步也就不会产生线程锁竞争,也就不会出现没完没了的ClassNotFoundException异常。

值得注意的是JBoss在防止线程锁竞争方面做出了很大的改进,不过重复的类加载的尝试仍然会在一定程度上影响应用的性能,因为搜索JAR包查找Java类会有一定的IO开销,因此也仍需要采取正确的手段进行处理。

希望你能喜欢这篇文章并且对类加载可能会带来的性能影响也有了更好的了解。JDK1.7和现代的Java EE容器都在类加载方面做了很多的优化,比如死锁和锁竞争方面,但是还是会存在潜在的问题。因此,我强烈建议你能密切的关注你的应用程序的表现,记录日志并确保类加载相关的异常比如java.lang.ClassNotFoundException和java.lang.NoClassDefFoundError都能够正确的处理。

大数据的发展带来了不容忽视的挑战

 


大数据研究领域可谓炙手可热,然而对数据中的价值加以利用仍然充满挑战。今天,我们将对此类挑战进行详尽解析。

大数据的生成速度令人错愕,事实上90%的可用数据是在过去两年当中才刚刚出现。如今我们需要努力分析大数据,从而发现其中可用以指导决策及战略性业务转型的洞察结论。

大数据应用已经开始在改进产品、提升服务水平及客户服务等领域发挥作用。下面来看一组具体数字:只有17%的企业尚无任何计划建立大数据项目,而超过70%的企业已经开始使用大数据——包括将其整合至业务当中,或者作为试水性项目。数据技术正在逐步成熟,亦有越来越多组织机构准备将其纳入信息管理与分析基础设施当中。

 

然而,以下大数据带来的“大挑战”同样不容忽视。

找到用于交流大数据的语言

各类科学,包括化学乃至数学都凭借着一种特定语言的出现而获得巨大的推动作用。很明显,我们必须在大数据找到同样值得依赖的特定语言,从而像使用代数符号以及合适的编程语言那样更好地对其加以分析。

提升数据可靠性

随着可用数据量的不断增长,我们必须有效区分“数据”的“信号”以及“有价值信息”。遗憾的是,截至目前仍有很多企业难以找到最理想的数据以及具体使用方式。这区分“垃圾数据”与保障数据质量已经成为一大关键性难题。

数据访问

数据访问与连接性同样是一大障碍。麦肯锡公司调查显示,目前仍有大量数据点未能接入网络,因此企业往往还不具备管理整体业务所必需的数据平台。

将更多复杂数据纳入进来

如果说大数据的起步阶段是在同“简单”数据作斗争(例如数字表以及图形等),那么如今需要处理的数据正变得愈发复杂:图片、视频以及对物理乃至生活环境的描述等等。因此,我们有必要重新审视并构建大数据工具及架构,用以捕捉、存储并分析多样性数据。

更好地整合时间变量

时间维度亦是大数据发展中的一大重要挑战,即如何分析长期因果关系,而不仅仅是处理实时数据流。最后,这一问题亦会给存储领域带来挑战。我们需要认真选择以切实承载如此庞大的数据存储量。

IT架构

数据世界的技术环境正在快速发展,因此能够有价值数据的前提在于同拥有强大创新能力的技术伙伴开展合作,从而建立正确的IT架构以高效适应各类变化因素。

安全性

最后但同样的重要的是安全问题。我们需要利用团队中每位成员的对应身份进行数据访问管理,同时配合适当的数据加密机制,从而避免各类潜在风险。

大数据技术带来的规模化趋势同样给科学、经济以及政治等领域带来深远影响,甚至给人类的发展轨迹打上了深深的烙印。大数据正挑战我们的分析能力以及对世界的认知方式。因此在迎接变化及不断成长的同时,我们亦应当坚守以人为本的原则,立足精益、与时俱进、秉持诚信并服务于整个世界。

香港葵芳机房,自有物业,自建机房;BGP混合线路,网络稳定,IP资源丰富,机房提供7×24小时的售后服务,免费重装系统,不限流量,最低只需198元每月,有需要的可以联系我哦。QQ2851041311 tel:18376476276

以上是关于不容忽视的ClassNotFoundException的主要内容,如果未能解决你的问题,请参考以下文章

Maven详解

开源安全问题不容忽视

共济失调患者饮食不容忽视

企业上云后,不容忽视的管理工具-云管平台

kotlin不容忽视的小细节

能成大事,实力不容小觑的星座都有哪些?