我偶然发现了与StringBuilder
的{{1}}方法相关的奇怪性能问题。我注意到似乎是一个愚蠢的错误 - 使用append
构造函数时的字符串连接(这甚至在NetBeans IDE中显示为警告)。
版本1
StringBuilder
在运行时期间创建了数百万个这样的对象,所以我想通过进行以下更改,它会提供一些加速:
版本2
int hash = -1; //lazily computed, also present in Version 2
int blockID = ... //0 to 1000, also present in Version 2
int threadID = ... //0 to 1000, also present in Version 2
boolean hashed = false; //also present in Version 2
@Override
public int hashCode(){
if(!hashed){
StringBuilder s = new StringBuilder(blockID+":"+threadID);
hash = s.toString().hashCode();
hashed= true;
}
return hash;
}
错误!事实证明,版本2实际上比版本1慢100倍。为什么???
其他信息
我正在编译Java 6(客户需求),我正在使用Oracle的JVM。
我的性能测试涉及创建一百万个这些对象并将它们放入HashMap中。使用版本1需要半秒钟,但使用版本2需要几乎50秒。
答案 0 :(得分:14)
因为您无意中设置了StringBuilder
的初始容量,而不是将blockID
附加到其中。请参阅constructor documentation here。
public StringBuilder(int capacity)
构造一个没有的字符串生成器 其中的字符和容量指定的初始容量 参数。
请改为尝试:
StringBuilder s = new StringBuilder(9);
s.append(blockID).append(':').append(threadID);
答案 1 :(得分:1)
你需要检查你的测试,因为你的第一个案例确实在做。
public int hashCode(){
if(!hashed){
StringBuilder s = new StringBuilder(
new StringBuilder(blockID).append(":").append(threadID).toString());
hash = s.toString().hashCode();
hashed= true;
}
return hash;
}
换句话说,它在第二种情况下做的更多,所以它会更慢。
简而言之,我怀疑你的测试是错误的,而不是你的表现更好。