V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
amiwrong123
V2EX  ›  Java

ConcurrentHashMap 构造器为啥要这么处理?

  •  
  •   amiwrong123 · 2020-07-08 23:16:16 +08:00 · 2404 次点击
    这是一个创建于 1606 天前的主题,其中的信息可能已经有所发展或是发生改变。
        public ConcurrentHashMap(int initialCapacity) {
            if (initialCapacity < 0)
                throw new IllegalArgumentException();
            int cap = ((initialCapacity >= (MAXIMUM_CAPACITY >>> 1)) ?
                       MAXIMUM_CAPACITY :
                       tableSizeFor(initialCapacity + (initialCapacity >>> 1) + 1));
            this.sizeCtl = cap;
        }
    

    tableSizeFor 的道理我都懂,这和 hashmap 一样,但这里为啥不是直接传递 initialCapacity 给 tableSizeFor 呢?

    我把两种情况对比了一下,发现好像也没啥规律啊?

    1 ==> 1 	 1 ==> 2 ==> 2
    2 ==> 2 	 2 ==> 4 ==> 4
    3 ==> 4 	 3 ==> 5 ==> 8
    4 ==> 4 	 4 ==> 7 ==> 8
    5 ==> 8 	 5 ==> 8 ==> 8
    6 ==> 8 	 6 ==> 10 ==> 16
    7 ==> 8 	 7 ==> 11 ==> 16
    8 ==> 8 	 8 ==> 13 ==> 16
    9 ==> 16 	 9 ==> 14 ==> 16
    10 ==> 16 	 10 ==> 16 ==> 16
    11 ==> 16 	 11 ==> 17 ==> 32
    12 ==> 16 	 12 ==> 19 ==> 32
    13 ==> 16 	 13 ==> 20 ==> 32
    14 ==> 16 	 14 ==> 22 ==> 32
    15 ==> 16 	 15 ==> 23 ==> 32
    16 ==> 16 	 16 ==> 25 ==> 32
    17 ==> 32 	 17 ==> 26 ==> 32
    18 ==> 32 	 18 ==> 28 ==> 32
    19 ==> 32 	 19 ==> 29 ==> 32
    20 ==> 32 	 20 ==> 31 ==> 32
    21 ==> 32 	 21 ==> 32 ==> 32
    22 ==> 32 	 22 ==> 34 ==> 64
    23 ==> 32 	 23 ==> 35 ==> 64
    24 ==> 32 	 24 ==> 37 ==> 64
    25 ==> 32 	 25 ==> 38 ==> 64
    26 ==> 32 	 26 ==> 40 ==> 64
    27 ==> 32 	 27 ==> 41 ==> 64
    28 ==> 32 	 28 ==> 43 ==> 64
    29 ==> 32 	 29 ==> 44 ==> 64
    30 ==> 32 	 30 ==> 46 ==> 64
    31 ==> 32 	 31 ==> 47 ==> 64
    32 ==> 32 	 32 ==> 49 ==> 64
    33 ==> 64 	 33 ==> 50 ==> 64
    34 ==> 64 	 34 ==> 52 ==> 64
    35 ==> 64 	 35 ==> 53 ==> 64
    36 ==> 64 	 36 ==> 55 ==> 64
    
    9 条回复    2020-07-09 09:40:27 +08:00
    luckyrayyy
        1
    luckyrayyy  
       2020-07-08 23:24:57 +08:00
    虽然我没记住你的 ID,但是一看问题就有预感是谁提问的....老哥加油
    sujin190
        2
    sujin190  
       2020-07-08 23:28:12 +08:00
    内存对齐,还有现在大部分内存分配管理器都是 2 的倍数分配的,不这样处理那就白白浪费内存了
    amiwrong123
        3
    amiwrong123  
    OP
       2020-07-08 23:32:10 +08:00 via Android
    @luckyrayyy
    是因为我经常发源码讨论的帖子吗😂
    amiwrong123
        4
    amiwrong123  
    OP
       2020-07-08 23:34:06 +08:00 via Android
    @sujin190
    可是直接传递 initialCapacity 给 tableSizeFor,结果也是 2 的幂啊
    AmmeLid
        5
    AmmeLid  
       2020-07-09 00:26:47 +08:00 via iPhone
    2==>2,依照你的算法设置容量为 2 的话,放入第二个元素的时候就超过负载触发一次扩容了吧
    amiwrong123
        6
    amiwrong123  
    OP
       2020-07-09 08:43:08 +08:00 via Android
    @AmmeLid
    好吧,是你这个意思。有点像是除以 0.75 再向上取整的感觉,不完全和 除以 0.75 再向上取整 一样
    Hyseen
        7
    Hyseen  
       2020-07-09 08:56:52 +08:00   ❤️ 3
    这是个 bug,在 11 中已经修复了
    https://bugs.openjdk.java.net/browse/JDK-8202422
    sujin190
        8
    sujin190  
       2020-07-09 09:39:15 +08:00
    @amiwrong123 #4 不是 2 的幂,你可以查一下大部分分配器的实现,大部分都是 2 4 8 16 32 这样分配的,倍数,虽然会浪费一些内存,但是内存碎片少,分配管理效率高
    amiwrong123
        9
    amiwrong123  
    OP
       2020-07-09 09:40:27 +08:00
    @Hyseen
    好吧,原来如此。。bug 修正后,最起码两种构造器结果一样了
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2346 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 33ms · UTC 01:49 · PVG 09:49 · LAX 17:49 · JFK 20:49
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.