【问题标题】:Updating (and Iterating) a Map in Java在 Java 中更新(和迭代)地图
【发布时间】:2013-10-27 10:07:18
【问题描述】:

我在 Java 7 recipes to update and iterate a Map 同时看过这本书:

ConcurrentMap<Integer,String> concurrentMap = new ConcurrentHashMap<Integer, String>();
for (int i =0;i < 1000;i++) {
  startUpdateThread(i, concurrentMap);
}
try {
  Thread.sleep(1000);
} catch (InterruptedException e) {
  e.printStackTrace();
}
for (Map.Entry<Integer, String> entry : concurrentMap.entrySet()) {
  System.out.println("Key :"+entry.getKey()+" Value:"+entry.getValue());
}

以及更新地图的方法如下:

private void startUpdateThread(int i, final ConcurrentMap<Integer, String> concurrentMap) {
    Thread thread = new Thread(new Runnable() {
        public void run() {
            while (!Thread.interrupted()) {
                int randomInt = random.nextInt(20);
                concurrentMap.put(randomInt, UUID.randomUUID().toString());
            }
} });
    thread.setName("Update Thread "+i);
    updateThreads.add(thread);
    thread.start();
}

我尝试过仅使用 HashMap 而不是 ConcurrentHasMap,结果是相同的(使用 Java VisualVM 进行监控)。有谁知道为什么?

谢谢, 奥古斯丁

更新:几个有趣的问题:

  1. 如果HashMap的容量是恒定的,下面哪些操作可以安全执行?
    • 两个线程更新 HashMap 中的值。
    • 两个线程更新 HashMap 中的值,而第三个线程正在读取 HashMap。
  2. 如果我想要快速更新地图,那么在只有 4 个处理器的计算机中拥有超过 4 个线程是否有意义?

【问题讨论】:

  • “使用 Java VisualVM 监控”是什么意思?
  • 当您插入随机内容时,我不明白您如何得出结果相同的结论?
  • 那么你的问题是什么?如果结果相同,有什么问题?那你的期望是什么?
  • @Enno,我所说的“使用 Java VisualVM 监控”的意思是我使用 VisualVM 监控线程和内存堆。尽管有 1000 个线程,但只有少数处于“运行”状态,其余处于“监控”状态。例如,对于 10 个线程,您有:i.imgur.com/Jftm6sD.png
  • @fvu 和 Adrian,我的意思是他们都可以工作。

标签: java concurrency map


【解决方案1】:

ConcurrentHashMap 允许多线程访问,而 HashMap 不允许。

同时从多个线程调用HashMap#put 可能会破坏您的地图。 ConcurrentHashMap 处理这些场景并缓解竞争条件。

特别是对于您的测试,您的地图只有 20 个键,这意味着它会相对较快地填满。 hashmap 的弱点是当你需要扩展存储桶空间的同时又放另一个条目时。尝试将密钥数量增加到Integer.MAX_VALUE,您将有更高的机会看到它被破坏。

【讨论】:

    【解决方案2】:

    下面的代码会给你一个不同的结果。您的代码不会崩溃的原因是 20 个整数的小随机间隔。因此,您的地图会立即变满,并且在此之后它的键集不会被修改。我将随机间隔更改为 10000 并添加了睡眠,所以现在它在程序运行期间不断更新,并在 HashMap 崩溃。它适用于ConcurrentHashMap,它能够迭代正在修改的数据。

    public class Test {
        static List<Thread> threadList = new ArrayList<>();
    
        public static void main(String[] args) throws InterruptedException {
            Map<Integer,String> map = new HashMap<>();
            for (int i =0;i < 1000;i++) {
                startUpdateThread(i, map);
            }
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    
            for (Map.Entry<Integer, String> entry : map.entrySet()) {
                System.out.println("Key :"+entry.getKey()+" Value:"+entry.getValue());
            }
    
            for (Thread thread : threadList) {
                thread.interrupt();
            }
        }
    
        private  static void startUpdateThread(int i, final Map<Integer, String> concurrentMap) {
            Thread thread = new Thread(new Runnable() {
                public void run() {
                    Random random = new Random();
                    while (true) {
                        int randomInt = random.nextInt(10000);
                        concurrentMap.put(randomInt, UUID.randomUUID().toString());
                        try {
                            Thread.sleep(100);
                        } catch (InterruptedException e) {
                            return;
                        }
                    }
                } });
    
            threadList.add(thread);
    
            thread.setName("Update Thread " + i);
            thread.start();
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2022-11-19
      • 1970-01-01
      • 1970-01-01
      • 2020-06-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-05-27
      相关资源
      最近更新 更多