TreeMap、Comparator与性能问题:带Comparator的TreeMap初始化耗时过长
为什么带Comparator的TreeMap初始化耗时远超自然排序版本?
嗨,这个现象我之前排查过,确实容易让人摸不着头脑——明明逻辑上都是用自然排序,怎么带Comparator的版本初始化慢这么多?先把你的测试代码补全(应该是截断了),方便大家理解场景:
public static void main(String[] args) { // 测试自然排序TreeMap初始化 final long millis1 = System.currentTimeMillis(); final TreeMap<Integer,Integer> natural = new TreeMap<>(); final long millis2 = System.currentTimeMillis(); System.out.println("自然排序TreeMap初始化耗时: " + (millis2 - millis1) + "ms"); // 测试带Comparator的TreeMap初始化 final long millis3 = System.currentTimeMillis(); final TreeMap<Integer,Integer> withComparator = new TreeMap<>(Comparator.naturalOrder()); final long millis4 = System.currentTimeMillis(); System.out.println("带Comparator的TreeMap初始化耗时: " + (millis4 - millis3) + "ms"); }
核心原因:延迟加载的类初始化开销
其实问题根本不在TreeMap本身,而是类加载机制在搞事情:
- 自然排序的TreeMap依赖的是
Comparable接口,这是JDK启动时就会加载的核心类,早就完成了初始化,所以创建TreeMap时几乎没有额外开销 - 而
Comparator.naturalOrder()返回的是java.util.Comparator$NaturalOrderComparator——这是一个静态内部类,第一次调用naturalOrder()时才会触发它的类加载、验证、初始化流程,包括静态字段的赋值、类构造器执行等,这些额外的耗时全被算在了TreeMap的初始化时间里
验证方法:提前触发类加载
你可以试试把Comparator的调用放在测试最前面,提前支付类加载的开销:
public static void main(String[] args) { // 提前加载NaturalOrderComparator类 Comparator.naturalOrder(); // 再执行测试 final long millis1 = System.currentTimeMillis(); final TreeMap<Integer,Integer> natural = new TreeMap<>(); final long millis2 = System.currentTimeMillis(); System.out.println("自然排序TreeMap初始化耗时: " + (millis2 - millis1) + "ms"); final long millis3 = System.currentTimeMillis(); final TreeMap<Integer,Integer> withComparator = new TreeMap<>(Comparator.naturalOrder()); final long millis4 = System.currentTimeMillis(); System.out.println("带Comparator的TreeMap初始化耗时: " + (millis4 - millis3) + "ms"); }
这时候你会发现两次初始化的耗时几乎一致,因为类加载的开销已经提前完成了。
额外提醒:微基准测试要严谨
用System.currentTimeMillis()做单次测试其实不太严谨,容易受到JVM预热、GC等因素影响。如果要做准确的性能对比,建议用JMH(Java Microbenchmark Harness)来编写测试,它会自动处理预热、多次迭代统计等问题,结果更可靠。
另外,这种初始化耗时的差异只会出现在第一次创建带该Comparator的TreeMap时,后续创建实例时因为类已经加载完成,耗时就会和自然排序版本差不多了。如果业务中需要多次创建这类TreeMap,建议提前初始化一个Comparator实例复用,避免每次都触发类加载的开销。
内容的提问来源于stack exchange,提问作者Priv
相关产品推荐
相关产品推荐

