博客
关于我
为什么阿里巴巴建议集合初始化时,指定集合容量大小
阅读量:425 次
发布时间:2019-03-06

本文共 1373 字,大约阅读时间需要 4 分钟。

HashMap容量设置与性能优化

在Java开发中,HashMap是最常用的非同步集合类,其性能至关重要。关于HashMap容量设置的选择,阿里巴巴Java开发手册中提到一个重要建议:在已知HashMap中将要存放的元素数量时,设置合理的初始容量可以显著提升性能。本文将深入分析这个问题,并提供实用的容量设置策略。


为什么要设置HashMap的初始化容量?

HashMap的性能瓶颈主要体现在两方面:一是哈希冲突的概率,二是扩容时的性能开销。默认情况下,HashMap的容量设置为16,这在处理大规模数据时往往不足以应对需求,导致频繁的扩容操作。

通过代码测试可以观察到,未初始化容量的HashMap在存储大量数据时表现出明显的性能下降。例如,在存储10亿个键值对时,未初始化容量的HashMap耗时较长,而初始容量设置为5千万或10亿时,性能显著提升。这证明了合理的容量设置能够有效减少扩容的频率,从而提高整体性能。


HashMap容量的计算机制

HashMap的容量计算机制有一些值得注意的细节。传统的初始化容量设置并非直接使用用户指定的值,而是经过一系列计算后得到一个第一个大于该值的2的幂。具体来说:

  • 计算逻辑

    容量计算的逻辑如下:

    int n = cap - 1;
    n |= n >>> 1;
    n |= n >>> 2;
    n |= n >>> 4;
    n |= n >>> 8;
    n |= n >>> 16;
    return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;

    这段代码的作用是找到一个大于cap的最小2的幂数。例如,cap为5时,计算结果为8;cap为9时,计算结果为16。

  • 特殊处理

    该逻辑在JDK 1.7和1.8中有所不同。在1.7中,容量设置会在第一次put操作时生效,而在1.8中,容量设置会直接生效。这一点需要开发者注意,尤其是在跨版本兼容性要求较高的项目中。


  • HashMap容量的合理设置

    在已知将要存储的元素数量(expectedSize)的情况下,如何选择合适的容量是一个关键问题。《阿里巴巴Java开发手册》建议采用以下公式计算初始容量:

    int capacity = (expectedSize / 0.75F) + 1;

    这个公式考虑了HashMap默认的负载因子(0.75),确保在存储元素时减少扩容的次数。例如,当expectedSize为10时,计算结果为14,这样可以避免在存储6个元素时就触发扩容的情况。


    总结

    在开发过程中,合理设置HashMap的初始容量可以显著提升性能。但需要注意的是,JDK会对初始容量进行自动调整,最终返回一个大于指定值的第一个2的幂数。因此,在实际应用中,可以通过公式expectedSize / 0.75F + 1.0F计算一个合理的初始容量。


    思考题:为什么JDK 8中putAll方法采用了expectedSize / 0.75F + 1.0F公式,而put方法并未采用这个公式?

    这背后反映了JDK在不同操作的性能优化策略。putAll方法需要一次性批量存储大量数据,因此采用较为保守的容量计算公式以确保稳定性。而put方法则更注重灵活性,允许用户根据具体需求动态调整容量。

    转载地址:http://prouz.baihongyu.com/

    你可能感兴趣的文章
    Netty工作笔记0027---NIO 网络编程应用--群聊系统2--服务器编写2
    查看>>
    Netty工作笔记0050---Netty核心模块1
    查看>>
    Netty工作笔记0057---Netty群聊系统服务端
    查看>>
    Netty工作笔记0060---Tcp长连接和短连接_Http长连接和短连接_UDP长连接和短连接
    查看>>
    Netty工作笔记0063---WebSocket长连接开发2
    查看>>
    Netty工作笔记0070---Protobuf使用案例Codec使用
    查看>>
    Netty工作笔记0077---handler链调用机制实例4
    查看>>
    Netty工作笔记0084---通过自定义协议解决粘包拆包问题2
    查看>>
    Netty工作笔记0085---TCP粘包拆包内容梳理
    查看>>
    Netty常用组件一
    查看>>
    Netty常见组件二
    查看>>
    netty底层源码探究:启动流程;EventLoop中的selector、线程、任务队列;监听处理accept、read事件流程;
    查看>>
    Netty心跳检测机制
    查看>>
    Netty核心模块组件
    查看>>
    Netty框架内的宝藏:ByteBuf
    查看>>
    Netty框架的服务端开发中创建EventLoopGroup对象时线程数量源码解析
    查看>>
    Netty源码—2.Reactor线程模型一
    查看>>
    Netty源码—3.Reactor线程模型三
    查看>>
    Netty源码—4.客户端接入流程一
    查看>>
    Netty源码—4.客户端接入流程二
    查看>>