关于结果的讨论
之所以使用非同步的StringBuilder是为了提供一个测量性能的基线我也想了解一下各种优化是否真的能够影响StringBuilder的性能正如我们所看到的StringBuilder的性能可以保持在一个不变的吞吐量水平上因为这些技术的目标在于锁的优化因此这个结果符合预期在性能测试的另一栏中我们也可以看到使用没有任何优化的同步的StringBuffer其运行效率比StringBuilder大概要慢三倍
仔细观察图的结果我们可以注意到从左到右性能有一定的提高这可以归功于EliminateLocks不过这些性能的提升比起偏向锁来说又显得有些苍白事实上除了C列以外每次运行时如果开启偏向锁最终都会提供大致相同的性能提升但是C列是怎么回事呢?
在处理最初的数据的过程中我注意到有一项测试在六个测试中要花费格外长的时间由于结果的异常相当明显因此基准测试似乎在报告两个完全不同的优化行为经过一番考虑我决定同时展示出高值和低值(B列和C列)由于没有更深入的研究我只能猜测这里应用了一种以上的优化(很可能是两种)并且存在一些竞争条件偏向锁大多时候会取胜但不非总能取胜如果另一种优化占优了那么偏向锁的效果要么被抑制要么就被延迟了
这种奇怪的现象是逸出分析导致的明确了这个基准测试的单线程化的本质后我期待着逸出分析会消除锁从而将StringBuffer的性能提到了与 StringBuilder相同的水平但是很明显这并没有发生还有另外一个问题在我的机器上每一次运行的时间片分配都不尽相同更为复杂的是我的几位同事在他们的机器上运行这些测试得到的结果更混乱了在有些时候这些优化并没有将程序提速那么多
前期的结论
尽管图列出的结果比我所期望的要少但确实可以从中看出各种优化能够除去锁产生的大部分开销但是我的同事在运行这些测试时产生了不同的结果这似乎对测试结果的真实性提出了挑战这个基准测试真的测量锁的开销了么?我们的结论成熟么?或者还有没有其他的情况?在本文的第二部分里我们将会深入研究这个基准测试力争回答这些问题在这个过程中我们会发现获取结果并不困难困难的是判断出这些结果是否可以回答前面提出的问题
public class LockTest { private static final int MAX = ; // million
public static void main(String[] args) throws InterruptedException { // warm up the method cache
for (int i = ; i < MAX; i++) {
concatBuffer(Josh James Duke);
concatBuilder(Josh James Duke);
}
Systemgc();
Threadsleep();
Systemoutprintln(Starting test);
long start = SystemcurrentTimeMillis();
for (int i = ; i < MAX; i++) {
concatBuffer(Josh James Duke);
}
long bufferCost = SystemcurrentTimeMillis() start;
Systemoutprintln(StringBuffer: + bufferCost + ms);
Systemgc();
Threadsleep();
start = SystemcurrentTimeMillis();
for (int i = ; i < MAX; i++) {
concatBuilder(Josh James Duke);
}
long builderCost = SystemcurrentTimeMillis() start;
Systemoutprintln(StringBuilder: + builderCost + ms);
Systemoutprintln(Thread safety overhead of StringBuffer:
+ ((bufferCost * / (builderCost * )) ) + %\n);
}
public static String concatBuffer(String s String s String s) { StringBuffer sb = new StringBuffer();
sbappend(s);
sbappend(s);
sbappend(s);
return sbtoString();
}
public static String concatBuilder(String s String s String s) {
StringBuilder sb = new StringBuilder(); sbappend(s); sbappend(s); sbappend(s); return sbtoString();
}
}
[] [] [] []