Java 返回线程安全类中的对象

Java 返回线程安全类中的对象,java,concurrency,thread-safety,Java,Concurrency,Thread Safety,我遇到了一个问题,似乎表明Java对象不是在我期望的堆上创建的。简短的版本是,我有一个JMS onMessage()方法,它调用另一个方法,根据TextMessage的JSon负载实例化适当的对象(routingCommand) public void onMessage(Message message) throws RuntimeException { IRoutingCommand routingCommand = null; routingCommand = instantia

我遇到了一个问题,似乎表明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消息被多次“process()ed”。当我将maxConcurrentConsumers设置为1时,不会发生这种情况

我在互联网上发现了这颗我不知道的智慧宝石,但假设它是正确的,它可以解释我的问题:

对对象的本地引用有点不同。引用本身不共享。但是,引用的对象并不存储在每个线程的本地堆栈中。所有对象都存储在共享堆中

InstanceRoutingCommand方法大约有50行长——这就是为什么我首先将其拆分。我可以充分检查JMS消息,以确定它表示的对象类型,并在onMessage()方法中对其进行实例化,然后将InstanceRoutingCommand转换为仅在传递的对象上使用setter。这将符合上述规定。但是,即使这样也不完全是琐碎的,并且会使onMessage()方法变得混乱


我没有尝试使对象不稳定或使任何东西同步,因为如果上述是真的,那么我看不到任何帮助。那么,在多线程对象中处理传递对象的最佳方法是什么呢?

您必须同步对多个线程引用的对象的访问,或者为每个线程提供自己的副本。虽然后者可能是唯一有效的解决方案,但应注意复制的对象不包含也包含在被复制对象中的引用。

我最终为RoutingCommand的所有子类创建了克隆方法

然后在类上同步的块中使用它。因为实例化正确子类的方法只是一个解析器(没有I/O),所以阻塞所有线程并不特别麻烦

synchronized(FlowController.class) {
routingCommand = instantiateRoutingCommand(message).clone();  
}

这解决了我的线程安全问题。因此,上述返回对象位于共享堆上的观点事实上是正确的。

我想你是对的,如果你说的非不变意味着不可变。非不变意味着可变和变异。你在代码中使用的所有变量都是局部引用,这意味着它们不会在多个线程之间共享。所以,我看不出线程问题可能在哪里,除非你隐藏的一些行是真正重要的,“局部引用”是你在方法体中声明的变量。除非发布这些变量,否则多个线程无法访问这些变量。发布变量意味着将其值分配给非本地引用(即实例/类字段),同时充分尊重我在本网站上的noob状态,以及我从其他帖子拼凑出此解决方案的事实,你为什么要否决此帖子?基本上归结为多线程程序的响应必须是线程安全的。乞丐不能挑肥拣瘦,但这很难说明问题。我从来不知道返回的对象是在共享堆上创建的。我觉得这太棒了。老实说,这是一个相当大的架构错误。如果有比在课堂上同步更好的方法,我很想知道它是什么。我想可能是ThreadLocal的问题吧……我对此投了反对票,我没有评论我为什么这么做是绝对错误的。因为一段时间过去了,我真的不记得为什么。但我认为这是因为您确实存在多线程问题,您可以通过添加一些同步来解决这个问题,尽管根据您对问题的最初解释,应该不需要它。这可能意味着您通过改变线程交错来隐藏而不是消除某些海森堡。也就是说,您正在损害性能(因为您正在序列化线程),并且该错误在将来有时仍然会突然出现。