【发布时间】:2015-01-24 10:55:57
【问题描述】:
我遇到以下问题。以最简单的方式,我的 Web 应用程序中有一个 servlet 和一个 java 类。现在 java 类遍历列表,对每个元素应用一些逻辑。我还保留一个计数器来跟踪处理的元素。我将计数器值传播到 servlet 可以通过 setter 访问的另一个类。从我的 servlet 中,我执行 AJAX 调用以检索已处理元素的数量并显示进度条。
int counter = 0;
...
for(SecurityForWorkflow securityForWorkflow : newSecuritiesForWorkflow) {
...
WorkflowManager.getInstance().setProcessedSecurities(counter);
counter++;
...
}
问题是进度条不流畅,可能从1到56到100。 我的猜测是,JIT 通过看到没有人访问(获取)计数器并将增量移出循环来以某种方式优化流程。我得出了这个结论,因为调试循环时一切都很顺利(我假设调试时 JIT 无法更改流程)但是当我运行它并将值输出到带有时间戳的日志文件中时,计数器会立即从 0 增加到总值/同时即使你循环运行 20 秒(170 次迭代的情况)。
我的问题是是否可以禁用代码段的 JIT 优化(例如通过注释,但谷歌搜索表明它不是)或者可能通过语言构造/技巧强制非优化(我尝试将变量声明为静态,易失性,将循环放在同步块中,每次在新生成的线程中调用设置器,将设置器放在 try-catch 的 finally 块中,还有一些我现在不记得了,如果我放一个 Thread.sleep 就可以工作(1000)在循环中)。
更新:这是循环的代码
我还用WorkflowManager.getInstance().incProcessedSecurities(); 位更新了WorkflowManager.getInstance().setProcessedSecurities(counter); 结果是一样的
for(SecurityForWorkflow securityForWorkflow : newSecuritiesForWorkflow) {
ManualInteractionEntity manualInteractionEntity = null;
BondEntityStatus createdBond = null;
LegEntity createdLeg = null;
isin = securityForWorkflow.getIsin();
try {
automatedSecurityBuildingStatus = securityBuilder.createBondEntity(
isin, businessDay);
if(automatedSecurityBuildingStatus.getBondEntityStatus()
.getAssetType() != null
&& automatedSecurityBuildingStatus.getBondEntityStatus()
.getEcbStatus() != null) {
createdBond = automatedSecurityBuildingStatus.getBondEntityStatus();
}
else {
removeFromSecuritiesForWorkflow.add(securityForWorkflow);
}
} catch(Exception e) {
NabsLogger.getInstance().log(Level.WARNING, String.format("Exception"
+ " when creating security with isin: %s", isin), e);
continue;
}finally{
WorkflowManager.getInstance().incProcessedSecurities();
}
try {
createdLeg = createdBond.getLegEntities().get(0);
} catch (Exception e) {
createdLeg = createdBond.getLegEntityStatus();
}
if (createdBond.getSetupStatus().equals(
Constants.MANUAL_INTERACTION_NEEDED)) {
manualInteractionEntity = new ManualInteractionEntity();
securityForWorkflow.addStatus(
SecurityForWorkflow.STATUS_MANUAL_INTERACTION_NEEDED);
manualInteractionEntity.setId(createdBond.getId());
manualInteractionEntity.setCreation(true);
Set<String> manualInteractionFields = automatedSecurityBuildingStatus
.getManualInteractionRuleResults().keySet();
manualInteractionEntity.setManualInteractionFields(
new ArrayList<String>(manualInteractionFields));
manualInteractionEntities.add(manualInteractionEntity);
} else if (createdBond.getSetupStatus().equals(
Constants.CREATED_AUTOMATICALLY)) {
securityForWorkflow.addStatus(
SecurityForWorkflow.STATUS_AUTOMATICALLY_BUILT);
}
PaymentDateCalculatorModel paymentDateCalculatorModel =
new PaymentDateCalculatorModel();
paymentDateCalculatorModel.setAllDates(createdBond);
PaymentProfileCalculatorModel paymentProfileCalculatorModel =
new PaymentProfileCalculatorModel();
paymentProfileCalculatorModel.setAllPayments(createdBond);
entities.add(createdBond);
legs.add(createdLeg);
}
谢谢。
【问题讨论】:
-
将
counter作为参数传递给setProcessedSecurities是一种访问,并且不会被优化掉。我不会立即怀疑这里有任何与 JIT 优化相关的东西。这里发生了其他一些事情,涉及到您的 sn-p 中没有的代码。例如。如果有某种线程、事件缓存、高 CPU 负载、其他事情发生,比如说,调试模式下的日志记录为其他事情的发生提供了足够的延迟,这使得问题“似乎”消失了。我 99.999% 确定问题不是你想的那样。您可能需要自己进行一些认真的调试。 -
如果在 JITtted 时它没有按预期工作,你要么在你正在使用的 VM 中发现了一个错误,要么你的代码有一些线程问题——我强烈怀疑是后者。但是没有足够的代码来清楚地了解哪里出了问题。
-
也就是说,请参阅stackoverflow.com/questions/4004340/… 和oracle.com/technetwork/java/javase/tech/…(该页面上也有指向 Java 8 选项的链接)。如果您使用不同的 JVM,请参阅其相关文档以获取相关选项。 stackoverflow.com/questions/7738794/add-jvm-options-in-tomcat 描述了如何通过 Tomcat 设置 JVM 选项。
-
感谢您的回复。我尝试了link 中提到的选项,但没有帮助,所以我决定重新发布以获取更多信息。 @JasonC 然后我将深入研究代码。这是遗留代码,我绑定到 java6。我的一个猜测是,在它与 Thread.sleep(1000) 一起使用后,它是某种竞争条件。这肯定不是高 CPU 负载,我会检查事件缓存,但相同的代码在放入测试文件(不使用 servlet/进度条)并使用 JUnit 测试时会给出相同的结果。
-
您可以尝试在循环中打印计数器的值以及时间戳,并将这些值与您从 AJAX 获得的值进行比较。 AJAX 调用可能不像您想象的那样经常实现。另一个需要检查的想法是天气使计数器波动产生影响。