【问题标题】:Multithreaded legacy Java application's threads taking turns in order多线程遗留 Java 应用程序的线程按顺序轮流
【发布时间】:2021-02-01 17:48:13
【问题描述】:

TL;DR - 用户有错误(ORA-01438:值大于指定精度允许此列)。我无法在本地重新创建它,因为当我的机器运行多线程应用程序时,一次只有十个线程中的一个按顺序运行。此外,运行它通常会导致我的机器用完堆,即使为堆分配了 8GB,然后我碰巧遇到了 NullPointerException 而不是用户的问题。


我正在尝试调试多年前由不再存在的人编写的多线程遗留 Java 应用程序 (JDK 1.6)。它正在尝试将一些数据插入 Oracle DB。该应用程序通常在 Weblogic 11G 服务器上运行,大约需要 5 分钟才能完成运行计算。但是,在本地调试时,线程不会同时工作,它们会在我的本地机器上轮流工作。这使得运行时间从前面提到的 5 分钟变为约 1 小时,并且仍然设法用完堆(我给了它 8GB)或者如果幸运的话抛出 NullPointerException,但这不是业务用户的错误。本来想把它剪下来只用一个线程,反正都是轮流使用的,但是摸了一周之后,业务影响就变得真实了,我不能一直用锤子敲它。

鉴于我没有提供代码和代码,这可能是一个长镜头,但有人遇到过类似问题吗?特别是为什么线程会轮流。


编辑:用户的错误是违反约束的,所以我认为它正在修改输入的数据并做一些事情,比如增加额外的精度。

问题:应用程序的 10 个线程是按顺序工作而不是同时工作,并且代码可能包含内存泄漏,导致应用程序崩溃并且没有遇到业务用户遇到的约束违反异常的同一代码。

编辑 2:我怀疑线程权衡,而不是同时运行,可能会导致它们不在我的本地机器上运行垃圾收集?不过,如果我很幸运没有用完堆,它仍然不能解释我收到与业务用户不同的错误的问题。

【问题讨论】:

  • 我不是数据库人员,所以不太可能回答,但也许您可以多说一下“在...服务器上”和“本地”之间的区别。特别是在这两种情况下,应用程序如何连接到数据库?
  • 另外,除了连接上可能存在的差异之外,“尝试调试”与应用程序正常运行的方式有何不同?
  • 您使用的是什么 JVM?它们在服务器和您的机器上是否相同?将哪些参数传递给 JVM?他们是一样的吗?这个应用程序做了多少日志记录?像这样一个实现良好的应用程序将能够将日志记录级别设置为它会告诉您它在做什么的程度。 (致所有阅读本文的经理和技术主管:本周的业务影响是因为您没有在关键业务应用程序中强制实施正确的日志记录。在应用程序的生命周期中花费了多少时间来修复这样的事情?)
  • 如果代码不断地创建对象的新实例并且它们永远不会超出范围或没有被取消引用,那么是的,你会用完堆,但这表现为 OutOfMemoryError 而不是 NullPointerException。如果您看到 NullPointerException,那是因为您有一个为 null 的引用,这并不意味着您的内存已用完。这些是非常不同且不相关的问题。
  • 最好的办法是在像 yourkit java profiler(我个人最喜欢的)这样的分析器下运行代码。这将向您显示线程争用和内存使用情况。

标签: java multithreading concurrency java-6


【解决方案1】:

您的直觉很可能是正确的,它告诉您“线程”对您不利,而您的前任只是给您留下了一个他永远无法修复的不可行设计。

“最终的接收者,” 在所有情况下,“都是 [Oracle ...] 数据库。”无论应用程序在向它提出请求时做了什么,唯一重要的是它接收到的请求。显然,客户端正在与自己发生冲突,因此很可能根本没有理由拥有多个线程。

【讨论】:

  • 我认为我的本地环境导致多线程在并发工作方面失败,因为服务器设法在 5 分钟内吐出结果;当然,服务器有更多的处理能力,但我不认为它可以在 10 个不同步工作的线程中运行整个过程,就像我正在做的那样。我认为我的前任使它成为多线程的,因为它处理大量数字,并且将其拆分为 10 个不同的线程是有意义的,因为它正在处理数千个数据集。我确定我需要先解决异步问题。
  • @DarrelHolt 如果应用程序确实有竞争条件导致它在生产服务器上失败,并且在您调试它时它只在您的系统上运行单线程,那么您是 永远不会解决你系统上的问题,因为它永远不会在你的系统上显现出来。即使你确实让它在你的系统上运行多线程,考虑到你暗示的系统之间的差异,你仍然很有可能永远无法在你的系统上复制这个问题。
  • @AndrewHenle 用户正在从 DB 返回约束冲突:ORA-01438:大于指定精度的值允许此列。我很确定它正在对它提取的原始数据进行计算并首先做一些事情。我的预感是它通常对数据库进行精度太高的计算,但会自动截断以删除尾随的 0。但这一次原始数据有所不同。也许它无法删除它们,因为使用的精度水平产生的实际值不如以前那么精确,而开发人员没有预料到
  • @DarrelHolt 我强烈怀疑当您在开发系统上向应用程序提供完全相同的输入数据时,假设您在系统上没有获得相同的输出是安全的吗?您可以看到应用程序在生产环境中生成的 SQL 崩溃了吗?这意味着您必须以某种方式弄清楚应用程序为什么会这样做?
  • @AndrewHenle 我无法获得相同的输出,因为我的机器堆用完了,并且由于我的机器一次使用一个线程而导致用户出错的时间太长了.我可以看到原始 SQL 语句,但看不到它使用的值。我很确定它是休眠的,但我没有在控制台/日志上看到任何我期望的东西。否则,我只会追溯到那个。所以是的,我必须修复多线程、nullPointer 和真正的问题,或者只是修复 nullPointer,幸运的是没有泄漏我的所有内存,并设法命中引发异常的查询
猜你喜欢
  • 2013-12-14
  • 1970-01-01
  • 2018-10-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-29
  • 2020-02-21
相关资源
最近更新 更多