用Java更新(和迭代)Map

时间:2013-10-27 10:07:19

标签: java concurrency map

我在Java 7配方书中看到了这个代码,可以同时更新和迭代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. 如果我想要更新Map的速度,在只有4个处理器的计算机中拥有4个以上的线程是否有意义?

2 个答案:

答案 0 :(得分:2)

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

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

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

答案 1 :(得分:1)

下面的代码会给你一个不同的结果。您的代码不会崩溃的原因是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();
    }
}