我在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监控)。有谁知道为什么?
谢谢, 奥古斯丁
更新:一些有趣的问题:
答案 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();
}
}