1.构造两个线程
多线程并发扩容,每个线程都负责一段tab进行处理,最小的一段是16。因此16->32扩容时,只有一个线程进行扩展。
为了能获得两个线程并发调试的效果,需要直接将默认容量定位32。
public class CHMTest extends Thread {
static ConcurrentHashMap<Integer, Integer> map = new ConcurrentHashMap<>(32);
static AtomicInteger at = new AtomicInteger(1);
public void run()
{
if (Thread.currentThread().getName().equals("thread0")) {
System.out.println("thread 0");
for (int i = 1; i < 1000000; ++i){
map.put(28 + (i << 5), 28 + (i << 5));
map.put(21 + (i << 5), 21 + (i << 5));
}
} else if (Thread.currentThread().getName().equals("thread1")){
System.out.println("thread 1");
for (int i = 1; i < 1000000; ++i){
map.put(29 + (i << 5), 29 + (i << 5));
map.put(22 + (i << 5), 22 + (i << 5));
}
}
}
public static void main(String[] args) {
CHMTest t0 = new CHMTest();
t0.setName("thread0");
CHMTest t1 = new CHMTest();
t1.setName("thread1");
// CHMTest t2 = new CHMTest();
// CHMTest t3 = new CHMTest();
t0.start();
t1.start();
// t2.start();
// t3.start();
}
}
2.多线程调试方法
对于多线程调试来说,最重要的就是控制两个线程的执行顺序,我们要做的其实就是当另一个不处于调试状态的线程命中断点后,能先暂停,一直等到我去处理为止。
在断点处右键:
它提供了两种挂起的模式,默认的是All,只需要选中Thread,它就会一直等待到你处理它。
在这里切换线程:
3.多线程调试
-
step1.先打两个断点,F9运行一次
-
step2.再打addCount里面的transfer断点,运行直到扩容,此时tab大小为64,扩容是在48发生
-
step3.transfer()里面打断点,在helpTransfer里面的transfer处打断点;在线程thread1里面(此时使用F7/F8,F9会进行线程切换,没法控制)运行直到49变为的ForwardingNode
-
step4.在线程thread0里面F7/F8运行,因为28+32=60,此时60变为了ForwardingNode,所以会进入helpTransfer进行扩容,此时的transferIndex = 48,表明thread0扩容是从47开始向下的一个16大小的段(也即32-47)
运行几次,会发现47 46变为ForwardingNode
-
step5.此时再切换到thread1,使用F7/F8运行完48-63这段的扩容操作。继续向下的时候,会发现transferIndex=32,所以thread1接着处理16-31这一段,同时transferIndex变为16