Java并发进阶系列:深度讨论jdk1.8 ConcurrentHashMap并发环境下transfer方法桶位分配过程

📅 2026/7/28 21:58:59 👁️ 阅读次数 📝 编程学习
Java并发进阶系列:深度讨论jdk1.8 ConcurrentHashMap并发环境下transfer方法桶位分配过程

在前面有多篇关于jdk1.8的ConcurrentHashMap研究是基于源代码给出的深度分析,要知道多线程环境下的ConcurrentHashMap内部运行机制是相对复杂的,好在IDEA提供的相关断点和Debug功能确实好用,使得多线程调试起来直观,通过这种方式能加深多线程操作CHM的执行流程。

前期准备

这部内容请参考文章中的小节部分,本文不再累赘。

使用埋点打印法观测

此方法相对繁琐,难度并不大,要求使用者对源代码设计足够理解,否则埋点位置不佳影响观测效果

1、测试代码

packageconcurrent.demo;publicclassResizeStampBugTest{publicstaticvoidmain(String[]args){// 设置64个线程并发putintmaxThreads=64;// 初始容量为8,内部会被调整为16ConcurrentHashMap<Long,String>map=newConcurrentHashMap<>(8);for(inti=0;i<maxThreads;i++){Threadt=newThread(()->map.put(Thread.currentThread().getId(),Thread.currentThread().getName()));t.setName("Thread-"+i);t.start();// 因为多个线程并发执行不方便查看打印结果,可以让前一个线程领先后面线程一丁点,以便观察打印结果,当然也可以不需要,多执行几次看看打印结果即可。// Thread.sleep(1);}}}

可以看到这里ConcurrentHashMap类用的是项目concurrent.demo包下的ConcurrentHashMap.java 源码文件

2、更改桶位分配步长,将源码的16改为4,方便观察

privatestaticfinalintMIN_TRANSFER_STRIDE=4;// private static final int MIN_TRANSFER_STRIDE = 16;

3、transfer方法加入打印每个线程分配的桶位区间

elseif(U.compareAndSwapInt(this,TRANSFERINDEX,nextIndex,nextBound=(nextIndex>stride?nextIndex-stride:0))){bound=nextBound;i=nextIndex-1;advance=false;// 以下三行是新增代码Strings=String.format(