JMH之CopyOnWriteArrayList与ConcurrentLinkedQueue的性能测试
测试代码
@BenchmarkMode(Mode.Throughput)
@OutputTimeUnit(TimeUnit.MICROSECONDS)
@State(Scope.Benchmark)
public class TestList_JMH {
CopyOnWriteArrayList smallList = new CopyOnWriteArrayList();
ConcurrentLinkedQueue smallQueue = new ConcurrentLinkedQueue();
CopyOnWriteArrayList bigList = new CopyOnWriteArrayList();
ConcurrentLinkedQueue bigQueue = new ConcurrentLinkedQueue();
@Setup
public void setup(){
for (int i=0;i<10;i++){
smallList.add(new Object());
smallQueue.add(new Object());
}
for (int i=0;i<1000;i++){
bigList.add(new Object());
bigQueue.add(new Object());
}
}
@Benchmark
public void smallListGet(){
smallList.get(0);
}
@Benchmark
public void smallQueueGet(){
smallQueue.peek();
}
@Benchmark
public void smallListSize(){
smallList.size();
}
@Benchmark
public void smallQueueSize(){
smallQueue.size();
}
@Benchmark
public void smallListWrite(){
smallList.add(new Object());
smallList.remove(0);
}
@Benchmark
public void smallQueueWrite(){
smallQueue.add(new Object());
smallQueue.remove(0);
}
@Benchmark
public void bigListWrite(){
bigList.add(new Object());
bigList.remove(0);
}
@Benchmark
public void bigQueueWrite(){
bigQueue.add(new Object());
bigQueue.remove(0);
}
public static void main(String[] args) {
Options opt = new OptionsBuilder().include(TestList_JMH.class.getSimpleName())
.forks(4).build();
try {
new Runner(opt).run();
} catch (RunnerException e) {
e.printStackTrace();
}
}
}
测试结果
Benchmark Mode Cnt Score Error Units
TestList_JMH.bigListWrite thrpt 20 1.145 ± 0.043 ops/us
TestList_JMH.bigQueueWrite thrpt 20 0.001 ± 0.001 ops/us
TestList_JMH.smallListGet thrpt 20 1162.087 ± 96.210 ops/us
TestList_JMH.smallListSize thrpt 20 1491.125 ± 105.829 ops/us
TestList_JMH.smallListWrite thrpt 20 12.135 ± 0.206 ops/us
TestList_JMH.smallQueueGet thrpt 20 1224.323 ± 50.976 ops/us
TestList_JMH.smallQueueSize thrpt 20 109.864 ± 1.828 ops/us
TestList_JMH.smallQueueWrite thrpt 20 0.001 ± 0.001 ops/us
结论
在并发条件下,写的性能远远低于读。
对于CopyOnWriteArrayList来说,内部有1000个元素的时候,写的性能要低于只有10个元素的时候,但是依然优于ConcurrentLinkedQueue。
Get操作,两者的读取性能差不多。由于实现上的差异,CopyOnWriteArrayList的size()操作的性能要好于ConcurrentLinkedQueue。
所以,即便是有少量的写入,在并发场景下,复制的消耗依然要很小。在元素总量不大的时候,CopyOnWriteArrayList的性能要好于ConcurrentLinkedQueue。