原代码来自: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,由于对象属性及方法都是非同步的,值变化对于其他线程不可见,就会发生一些丢数据,集合大小记录不准确的问题。