为什么代码会挂起来自多个线程的HashMap.put()?

Nep*_*daj 7 java concurrency hashmap

我一直试图通过创建一个简单的单元测试来证明应用程序中存在一个错误,该测试将值放到地图上.我当时正在等待ConcurrentModificationException,但我所得到的只是在执行程序中悬挂线程,我看不出问题究竟在哪里.

测试在这里:

@Test
public void testHashMap() throws Exception {
    final Random rnd = new Random();
    final Map<String, Object> map = new HashMap<>();
    ExecutorService executor = Executors.newFixedThreadPool(10);
    for (int i = 0; i < 100; i++) {
        final int counter=i;
        executor.execute(new Runnable() {
            @Override
            public void run() {
                try{
                    for (int j = 0; j<1000; j++){
                        map.put(String.valueOf(rnd.nextLong()), new Object());
                        //map.put("A", new Object());
                    }
                    System.out.println("Thread "+counter+" finished");
                }catch(Exception e){
                    System.out.println("Thread "+counter+" failed with exception: ");
                    e.printStackTrace();
                }
            }
        });
    }
    executor.shutdown();
    int i = 0;
    while (!executor.isTerminated()) {
        i++;
        Thread.sleep(1000);
        System.out.println("Waited "+i+" seconds");
    }
}
Run Code Online (Sandbox Code Playgroud)

我知道我不应该这样做,但我不明白为什么我没有得到异常以及为什么线程只挂在那里?当我put在地图上做一个简单的(注释代码),然后它传递正常.

以下是示例输出:

Thread 0 finished
Thread 1 finished
Thread 4 finished
Thread 2 finished
Thread 5 finished
Thread 7 finished
Thread 9 finished
Thread 10 finished
Thread 13 finished
Thread 6 finished
Thread 14 finished
Thread 8 finished
Thread 12 finished
Thread 16 finished
Thread 19 finished
Thread 20 finished
Thread 21 finished
Thread 26 finished
Thread 25 finished
Thread 24 finished
Thread 28 finished
Thread 3 finished
Thread 31 finished
Thread 30 finished
Thread 32 finished
Thread 34 finished
Thread 35 finished
Thread 36 finished
Thread 37 finished
Thread 38 finished
Thread 39 finished
Thread 22 finished
Thread 27 finished
Thread 42 finished
Thread 43 finished
Thread 41 finished
Thread 45 finished
Thread 44 finished
Thread 47 finished
Thread 48 finished
Thread 49 finished
Waited 1 seconds
Waited 2 seconds
Waited 3 seconds
Waited 4 seconds
Waited 5 seconds
...indefinitely
Run Code Online (Sandbox Code Playgroud)

Gra*_*ray 8

为什么代码会挂起来自多个线程的HashMap.put()?

HashMap没有外部同步,您不能使用多线程.你应该切换到使用ConcurrentHashMap.

您也可以使用Collections.synchronizedMap(new HashMap<>());ConcurrentHashMap应该提供更好的性能.

我期待ConcurrentModificationException,但我得到的只是在执行程序中挂起线程,我没有看到问题究竟在哪里.

你看到一个挂起,因为其中一个线程有一个损坏的版本HashMap- 可能是一个循环链表,其中两个哈希条目相互链接或相互关联.如果进行线程转储,则会在遍历HashMap条目时看到它正在旋转.

ConcurrentModificationException如果只抛出HashMap检测的修改.通常,当您(例如)通过调用map.remove(...)而不是iterator.remove()在地图上迭代时删除条目时,这是单线程使用.

同步有两个重要的事项:互斥锁定和内存同步.每个处理器都有自己的内存缓存,线程可以轻松查看对象的部分同步视图(HashMap在本例中为您),而无需正确的内存同步.

唯一令人沮丧的是有时会引发异常,但大部分时间它都会挂起.

在多线程情况下,根据定义存在大量竞争条件,因为线程通常在多个处理器上并行运行.考虑到环境的并行性质,很难预测失败的类型.