原代码来自:https://www.codeleading.com/article/13746321102/

完整代码如下:

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.function.Consumer;

/**
 * <p>
 * </p>
 *
 * @author chandler
 * @since 2022/8/1
 */
public class ConcurrencyUtil {

    public static <T> void concurrencyExecute(int threadNumber, Consumer<T> consumer, T t) {
        CountDownLatch start = new CountDownLatch(1);
        CountDownLatch end = new CountDownLatch(threadNumber);
        ExecutorService executorService = Executors.newFixedThreadPool(threadNumber);
        for (int i = 0; i < threadNumber; i++) {
            executorService.submit(() -> {
                try {
                    // 先阻塞这别让这个线程跑起来
                    start.await();
                    // 具体的业务方法(本地方法 or 远程调用)
                    consumer.accept(t);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    Thread.currentThread().interrupt();
                } finally {
                    // 一个线程跑完 end计数器-1
                    end.countDown();
                }
            });
        }
        // start-1 所有线程启动,模拟并发
        start.countDown();
        // 阻塞直到所有线程执行完毕
        try {
            end.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
            Thread.currentThread().interrupt();
        }
        executorService.shutdown();
    }

    /**
     * 代码来自:https://www.codeleading.com/article/13746321102/
     * @param args
     */
    public static void main(String[] args) {
        for (int i1 = 0; i1 < 100; i1++) {
            Map<String, Integer> map = new HashMap<>();
            Map<String, Integer> cmap = new ConcurrentHashMap<>();
            ConcurrencyUtil.concurrencyExecute(100, item -> {
                for (int i = 0; i < 10; i++) {
                    String threadName = Thread.currentThread().getName();
                    item.put(threadName + i, i);
                    cmap.put(threadName + i, i);
                }
            }, map);
            System.out.println("HashMap: " + map.size());
System.out.println("ConcurrentHashMap: " + cmap.size());
System.out.println("================="); // result // map: 964 总是 <= 1000 // cmap: 1000 总是 == 1000 不会丢数据 } }

运行输出:

HashMap: 975
ConcurrentHashMap: 1000
=================
HashMap: 983
ConcurrentHashMap: 1000
=================
HashMap: 987
ConcurrentHashMap: 1000
=================
HashMap: 992
ConcurrentHashMap: 1000
=================
HashMap: 991
ConcurrentHashMap: 1000
=================
HashMap: 998
ConcurrentHashMap: 1000
=================
HashMap: 993
ConcurrentHashMap: 1000
=================

可以发现HashMap的最终结果总是不对的,原因也简单,HashMap 内部使用数组+链表+红黑树(1.8以后)保存数据,多线程插入数据,在hash冲突时修改链表、扩容时reHash,由于对象属性及方法都是非同步的,值变化对于其他线程不可见,就会发生一些丢数据,集合大小记录不准确的问题。