【发布时间】:2013-09-18 19:16:32
【问题描述】:
我遇到的问题似乎表明 Java 对象不是在我预期的堆上创建的。简短的版本是我有一个 JMS onMessage() 方法,它调用另一个方法来实例化基于 TextMessage 的 JSon 有效负载的正确对象 (routingCommand)。
public void onMessage(Message message) throws RuntimeException {
IRoutingCommand routingCommand = null;
routingCommand = instantiateRoutingCommand(message);
...
process(routingCommand);
}
private IRoutingCommand instantiateRoutingCommand(Message message) {
IRoutingCommand routingCommand = null;
... lots of code to build the correct type of RoutingCommand
routingCommand = new IeRoutingCommand(ieNotification);
return routingCommand;
}
问题在于,在我的负载测试期间,在极少数情况下,同一条 JMS 消息被多次“处理()”。当我设置 maxConcurrentConsumers=1 时,这不会发生。
我在互联网上发现了这个我从不知道的智慧宝藏,但假设它是正确的,它可以解释我的问题:
对对象的本地引用有点不同。引用本身不共享。然而,引用的对象并不存储在每个线程的本地堆栈中。所有对象都存储在共享堆中。
instantiateRoutingCommand 方法大约有 50 行长——这就是我一开始就把它分解的原因。我可以充分检查 JMS 消息以确定它代表什么类型的对象,并在 onMessage() 方法中对其进行实例化,并将 instantiateRoutingCommand 转换为仅在传递的对象上使用 setter。即满足上述规定。但即使这样也不是微不足道的,而且会弄乱 onMessage() 方法。
我没有尝试使对象变得易失或使任何东西同步,因为如果上述情况属实,那么我看不到任何帮助。那么在多线程对象中处理传递对象的最佳方法是什么?
【问题讨论】:
-
您在代码中使用的所有变量都是本地引用,这意味着它们不会在多个线程之间共享。所以,我看不出线程问题可能出在哪里,除非您隐藏的某些行是真正重要的行。
-
“局部引用”是您在方法体中声明的变量。这个变量不能被多个线程访问,除非你发布它们。发布变量意味着将其值分配给非本地引用(即实例/类字段)
标签: java concurrency thread-safety