简体   繁体   English

在线程安全类中返回一个Object

[英]Return an Object in a thread safe class

I am having a problem that appears to indicate Java objects aren't created on the heap I expected. 我遇到的问题似乎表明Java对象没有在我期望的堆上创建。 The short version is that I have a JMS onMessage() method that is calling another method to instantiate the proper object (routingCommand) based on the JSon payload of the TextMessage. 简短的版本是我有一个JMS onMessage()方法,它调用另一个方法来基于TextMessage的JSon有效负载实例化正确的对象(r​​outingCommand)。

    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;
}

The problem is that during my load test, on Extremely Rare occasions, the same JMS message is being "process()ed" multiple times. 问题是在我的负载测试期间,在极度罕见的情况下,相同的JMS消息被多次“处理()编辑”。 When I set maxConcurrentConsumers=1 this does not happen. 当我设置maxConcurrentConsumers = 1时,这不会发生。

I found this gem of wisdom on the Internet that I never knew but assuming it is correct it would explain my problem: 我在互联网上发现了这种智慧的宝石,我从来不知道,但假设它是正确的,它可以解释我的问题:

Local references to objects are a bit different. 对象的本地引用有点不同。 The reference itself is not shared. 引用本身不共享。 The object referenced however, is not stored in each threads's local stack. 但是,引用的对象不存储在每个线程的本地堆栈中。 All objects are stored in the shared heap. 所有对象都存储在共享堆中。

The instantiateRoutingCommand method is the around 50 lines long - that's why I broke it out to begin with. instantiateRoutingCommand方法大约有50行 - 这就是为什么我把它打破了。 I COULD examine the JMS message enough to figure out what type of object it represents and instantiate it in the onMessage() method and convert instantiateRoutingCommand to just use setters on the passed object. 我可以检查JMS消息,足以弄清楚它代表什么类型的对象,并在onMessage()方法中实例化它,并将instantiateRoutingCommand转换为仅在传递的对象上使用setter。 That would satisfy the above stipulation. 这将满足上述规定。 But even that is not entirely trivial and would clutter up the onMessage() method. 但即使这并非完全无关紧要,也会使onMessage()方法变得混乱。

I didn't try making the object volatile or making anything synchronized because if the above is true then I don't see any of that helping. 我没有尝试使对象易变或使任何同步,因为如果上述情况属实,那么我没有看到任何帮助。 So what's the best way to handle passing objects in a multi-threaded object? 那么在多线程对象中处理传递对象的最佳方法是什么?

You must either synchronize access to objects referenced by multiple threads or give each thread their own copy. 您必须同步访问多个线程引用的对象,或者为每个线程分配自己的副本。 While the later is potentially the only efficient solution, care should be taken that the copied object does not contain references also contained in the object being copied. 虽然后者可能是唯一有效的解决方案,但应注意复制的对象不包含也包含在被复制对象中的引用。

I ended up creating clone methods for all the subclasses of my RoutingCommand. 我最终为RoutingCommand的所有子类创建了克隆方法。

Then used that within a block synchronized on the class. 然后在类同步的块中使用它。 Since the method that instantiates the correct subclass is just a parser (no I/O) it was not particularly onerous to block all the threads. 由于实例化正确子类的方法只是一个解析器(没有I / O),因此阻塞所有线程并不是特别繁重。

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

This fixed my thread-safe problems. 这解决了我的线程安全问题。 So the above point that returned objects are on shared heap is in fact true. 所以返回对象的上述点在共享堆上实际上是正确的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM