从多个线程调用方法addEd时是否会出现争用情况?
private static Map<String , Long> table;
static {
table = new ConcurrentHashMap<String , Long>();
}
public static void addId(String key, Long value){
if(table.containsKey(key)){
table.remove(key);
}
table.put(key, value);
}
答案 0 :(得分:8)
没有什么可以阻止另一个线程在containsKey
/ remove
和put
之间放置一些值,因此在放置之前检查表是否已经包含一个键并不是真的“安全” (或者更确切地说,并没有“有意义”)。
你为什么不这样做
public static void addId(String key, Long value){
table.put(key, value);
}
无论如何, put
将覆盖任何先前的条目。
如果您不希望多个线程同时执行该方法,请将该方法声明为synchronized
。
答案 1 :(得分:2)
是
(似乎我的答案必须是30个字符或更多)
addId
调用可以提供竞争条件:一个线程可以尝试放置一个键,另一个线程可以同时删除一个键(如果它是相同的键,则可能是一个问题)。在这种方法中,还有一些案例可以让你获得竞争条件(带来各种后果)。
如果您使用其他方法对表执行其他操作(即从中读取),这可能会更复杂,并且它会使您的竞争条件比“仅”覆盖的值更糟糕。
归根结底,你在问什么?你想知道如何避免竞争条件吗?你的地图类的其他部分做了什么?
答案 2 :(得分:2)
是的,可能会出现竞争状况。
if(table.containsKey(key)){
table.remove(key);
}
table.put(key, value);
另一个线程可以修改containsKey,remove和put之间的表。在执行put()之前不需要调用remove(),但是 - 删除containsKey / remove并且它将是线程安全的。
答案 3 :(得分:0)
如果你想保证在替换旧值时使用旧值,那么竞争可能导致不处理所有被覆盖的键。
if(table.containsKey(key)){
Long oldValue = table.remove(key);
}
table.put(key, value);
if (oldValue != null)
importantOperation(oldValue);
修改强>
看起来put也会返回旧值(如果有的话),因此检查仍然没有必要(正如其他人指定的那样)。在以下尴尬的情况下进行检查是必要的,这将涉及赛车:
if(table.containsKey(key)){
Long oldValue = table.remove(key);
value = secretlyAdjustInput(oldValue, value)
}
table.put(key, value);