Java Hashmap - 多线程放(Java Hashmap - Multiple thread put)
我们最近在我的工作中讨论了是否需要使用ConcurrentHashMap,或者我们可以在多线程环境中简单地使用常规HashMap。 HashMaps的参数是两个:它比ConcurrentHashMap快,所以我们应该尽可能使用它。 而
ConcurrentModificationException
显然只会在你修改时迭代Map时出现,所以“如果我们只从地图中PUT和GET,那么常规HashMap有什么问题?” 是论据。我认为并发PUT操作或并发PUT和READ可能会导致异常,所以我组合了一个测试来证明这一点。 测试很简单; 创建10个线程,每个线程将相同的1000个键值对一次又一次地写入地图5秒钟,然后打印生成的地图。
结果实际上很混乱:
Length:1299 Errors recorded: 0
我认为每个键值对在HashMap中都是唯一的,但是通过查看地图,我可以找到多个相同的Key-Value对。 我期望某种异常或损坏的键或值,但我没有想到这一点。 这是怎么发生的?
这是我使用的代码,供参考:
public class ConcurrentErrorTest { static final long runtime = 5000; static final AtomicInteger errCount = new AtomicInteger(); static final int count = 10; public static void main(String[] args) throws InterruptedException { List<Thread> threads = new LinkedList<>(); final Map<String, Integer> map = getMap(); for (int i = 0; i < count; i++) { Thread t = getThread(map); threads.add(t); t.start(); } for (int i = 0; i < count; i++) { threads.get(i).join(runtime + 1000); } for (String s : map.keySet()) { System.out.println(s + " " + map.get(s)); } System.out.println("Length:" + map.size()); System.out.println("Errors recorded: " + errCount.get()); } private static Map<String, Integer> getMap() { Map<String, Integer> map = new HashMap<>(); return map; } private static Map<String, Integer> getConcMap() { Map<String, Integer> map = new ConcurrentHashMap<>(); return map; } private static Thread getThread(final Map<String, Integer> map) { return new Thread(new Runnable() { @Override public void run() { long start = System.currentTimeMillis(); long now = start; while (now - start < runtime) { try { for (int i = 0; i < 1000; i++) map.put("i=" + i, i); now = System.currentTimeMillis(); } catch (Exception e) { System.out.println("P - Error occured: " + e.toString()); errCount.incrementAndGet(); } } } }); } }
We've recently had a discussion at my work about whether we need to use ConcurrentHashMap or if we can simply use regular HashMap, in our multithreaded environment. The argument for HashMaps are two: it is faster then the ConcurrentHashMap, so we should use it if possible. And
ConcurrentModificationException
apparently only appears as you iterate over the Map as it is modified, so "if we only PUT and GET from the map, what is the problem with the regular HashMap?" was the arguments.I thought that concurrent PUT actions or concurrent PUT and READ could lead to exceptions, so I put together a test to show this. The test is simple; create 10 threads, each which writes the same 1000 key-value pairs into the map again-and-again for 5 seconds, then print the resulting map.
The results were quite confusing actually:
Length:1299 Errors recorded: 0
I thought each key-value pair was unique in a HashMap, but looking through the map, I can find multiple Key-Value pairs that are identical. I expected either some kind of exception or corrupted keys or values, but I did not expect this. How does this occur?
Here's the code I used, for reference:
public class ConcurrentErrorTest { static final long runtime = 5000; static final AtomicInteger errCount = new AtomicInteger(); static final int count = 10; public static void main(String[] args) throws InterruptedException { List<Thread> threads = new LinkedList<>(); final Map<String, Integer> map = getMap(); for (int i = 0; i < count; i++) { Thread t = getThread(map); threads.add(t); t.start(); } for (int i = 0; i < count; i++) { threads.get(i).join(runtime + 1000); } for (String s : map.keySet()) { System.out.println(s + " " + map.get(s)); } System.out.println("Length:" + map.size()); System.out.println("Errors recorded: " + errCount.get()); } private static Map<String, Integer> getMap() { Map<String, Integer> map = new HashMap<>(); return map; } private static Map<String, Integer> getConcMap() { Map<String, Integer> map = new ConcurrentHashMap<>(); return map; } private static Thread getThread(final Map<String, Integer> map) { return new Thread(new Runnable() { @Override public void run() { long start = System.currentTimeMillis(); long now = start; while (now - start < runtime) { try { for (int i = 0; i < 1000; i++) map.put("i=" + i, i); now = System.currentTimeMillis(); } catch (Exception e) { System.out.println("P - Error occured: " + e.toString()); errCount.incrementAndGet(); } } } }); } }
原文:https://stackoverflow.com/questions/40805373