如何正确生成唯一ID并将其存储在ConcurrentHashMap中

时间:2017-02-21 09:18:52

标签: java concurrency concurrenthashmap

我目前正在使用ConcurrentHashMap,根据我使用org.apache.commons.lang.RandomStringUtils#randomAlphanumeric生成的唯一ID存储一些文件。

我目前的做法是:

private ConcurrentHashMap <String, CustomFile> fileIdMap = 
                     new ConcurrentHashMap <String, SwitchConfigurationFile>();

public void importFile () {       
    CustomFile file = new CustomFile (generateFileID(), param1, param2, param3, param4);
    fileIdMap.put (file.getID(), file);       
}

private String generateFileID () {
   String generatedValue = RandomStringUtils.randomAlphanumeric(5);
   while (fileIdMap.containsKey(generatedValue)) {
       generatedValue = RandomStringUtils.randomAlphanumeric(5);
   }
   //I was thinking here to put the generated value into the Map
   //but at this moment I don't have the CustomFile instance
   //and null values are not allowed
   //maybe:
   //fileIdMap.put (generatedValue, new CustomFile());
   return generatedValue;
}

我在想:如果fileIdMap.containsKey(generatedValue)返回false并且在我将其添加到地图之前另一个线程出现并添加相同的键,我会在地图中有一个CustomFile而不是两个。我知道机会非常小,但我想考虑到这一点。

那么,在这种情况下最好的方法是什么?如何确保每个文件都有唯一的ID?

2 个答案:

答案 0 :(得分:2)

您可以使用putIfAbsent(K key, V value)

private String generateFileID () {
   CustomFile file = new CustomFile();
   String generatedValue = RandomStringUtils.randomAlphanumeric(5);
   while (fileIdMap.putIfAbsent(generatedValue, file) != null) {
       generatedValue = RandomStringUtils.randomAlphanumeric(5);
   }
   return generatedValue;
}

ConcurrentHashMap中此方法的实现正确synchronized,以避免出现并发问题。

答案 1 :(得分:0)

你可以使用#putIfAbsent(),它会以原子方式将项目放在地图中,否则返回null,这样你就可以放入你的while循环而不是null。
您需要稍微重构一下代码,因为您还没有CustomFile实例。
你可以做的一件事就是首先放置一个虚拟项目,然后在创建它之后用真实对象替换它,但如果其他线程同时读取该对象,这可能会导致另一个同步问题。