我对以下优化可能性有点好奇,但不知道如何自己验证,也许有人已经知道了答案。
我们的应用程序中有很多类似的代码。基本上它是一个由一些消息(MyStartingMessage
)启动的statefull处理程序(saga),稍后可以通过其他消息(MyCotinueMessage
)继续。因为StatefullHandler
有多个实例,我们要检查是否应该由给定实例处理Continue消息。因此我们在处理程序中设置了一些状态,当收到消息时,我们检查每个处理程序实例,如果消息中的状态与处理程序状态匹配,则只有消息由此处理程序实例处理。
在下面显示的示例中,某个框架将提取匹配器并检查其中是否有任何匹配接收到的继续消息实例。
因为我们每秒处理成千上万条这样的消息,所以我很好奇JVM是否确实优化了实例分配(一段时间后),每次都不创建新实例。
class StatefullHandler implements MessageHandler {
public void handle(final MyStartingMessage m) {
m.setState(m.getUserId()); // used by the matchers
}
public void handle(final MyContinueMessage m) {
// handle
}
// only returned for queries and never modified
public Collection<MessageMatcher> matchers() {
// message will only be handled by this instance if state matches
// is this new operator optimized 'away' after some time??
return ImmutableSet.of(MessageMatcher.for(MyContinueMessage.class, msg -> msg.getUserId()));
}
}
如果没有优化,我会有效地写这个:
class StatefullHandler implements MessageHandler {
private static final MATCHERS = ImmutableSet.of(
MessageMatcher.for(MyContinueMessage.class, msg -> msg.getUserId()));
public void handle(final MyStartingMessage m) {
m.setState(m.getUserId()); // used by the matchers
}
public void handle(final MyContinueMessage m) {
// handle
}
public Collection<MessageMatcher> matchers() {
return MATCHERS;
}
}
答案 0 :(得分:1)
如果您明确使用new
关键字,JVM无法重用旧的对象实例,因为这会违反Java语言规范。首先,当您通过A
创建对象B
和new
时,保证A == B
将返回false
。其次,它保证您可以独立地A
和B
同步,而无需相互等待。如果JVM重用旧对象,则无法保证。因此,即使对于new Integer(1)
等最简单的情况,JVM也无法重用它们。
在某些情况下,您可以依赖第三方库执行的缓存,但在您的特定情况下,Guava的ImmutableSet.of
仅将空对象重用现有对象。因此,在您的情况下,static
字段似乎是最佳解决方案。
答案 1 :(得分:1)
虽然JVM无法重用对象,但它可以避免首先创建它。
如果在内联之后(即查看你的调用者及其调用者等),你的对象会以同样的方式生存和死亡,它可以放在堆栈上,并可能使用Escape Analysis消除。
在你的情况下,完全有可能不对象of()
,但lambda对象也被删除,这不会创建任何对象。这完全取决于您的用例以及优化器是否可以消除对象创建。
我建议您使用商业分析器或Flight Recorder来检查对象是否实际创建。