多线程Java程序中HashMap大小不一致

问题描述 投票:0回答:1

我有一个多线程 Java 程序,其中每个线程都将唯一的键插入共享的

HashMap
中。但是,当我在所有线程执行完毕后检查
HashMap
的大小时,大小与预期的插入数量不一致。

这是代码:

public class CurrentHashMapDemo {
    private static final int NUM_THREADS = 5;
    private static final int NUM_INSERTIONS = 100;
    private static HashMap<String, Integer> hashMap = new HashMap<>();

    public static void main(String[] args) throws InterruptedException{
        ExecutorService executorService = Executors.newFixedThreadPool(NUM_THREADS);
        for(int i=0; i< NUM_THREADS; i++){
            executorService.execute(insertRecord());
        }
        executorService.shutdown();
        if(!executorService.isTerminated()){
            Thread.sleep(1000);
        }
        System.out.println("Size of the hashmap="+ hashMap.size());
    }

    private static Runnable insertRecord(){
        return () -> {
            for(int i=0; i<NUM_INSERTIONS; i++){
                System.out.println("Key:"+ i+Thread.currentThread().getName());
                hashMap.put(i+Thread.currentThread().getName(), i);
            }
        };
    }
}

在此代码中,我创建了

NUM_THREADS
数量的线程,每个线程都将
NUM_INSERTIONS
数量的记录插入到
HashMap
中。每条记录的键是循环索引
i
和当前线程名称的组合,对于每个线程来说应该是唯一的。

但是,当我在所有线程执行完毕后打印

HashMap
的大小时,大小并不一致
NUM_THREADS * NUM_INSERTIONS
。我知道
HashMap
不是线程安全的,并且我知道我可以使用
ConcurrentHashMap
来解决这个问题。但我有兴趣了解导致这种不一致行为的
HashMap
实现中到底发生了哪些竞争条件。

我正在使用 OpenJDK 17。谁能解释一下在这个特定 JDK 的 HashMap 实现中可能发生这种竞争条件的位置以及它如何影响 HashMap 的大小?

任何人都可以解释这种竞争条件可能发生在哪里以及它如何影响

HashMap
的大小?

感谢@user85421您的评论,我正在寻找相同的,

一种可能性:哈希映射的创建容量为 16,当容量耗尽时,必须重新组织(调整大小) - 如果两个线程同时执行此操作,则可能会出现混乱

java multithreading hashmap
1个回答
0
投票

这只是为了将评论中每个人所说的(正确的!)变成答案。 (因为你似乎想要继续。)

您的演示代码的问题是它不是线程安全的。您有多个线程正在更新指定为非线程安全的共享对象(

HashMap
)实例。这将导致未指定的行为。

您所看到的不一致行为的确切(详细)原因是“无关紧要的”。你认为演示“应该有效,因为”的论点与它不起作用的证据相悖! 修复(在实际应用程序中)是在外部同步

HashMap

,或使用

ConcurrentHashMap
    

© www.soinside.com 2019 - 2024. All rights reserved.