可以在下面的代码中出现竞争条件

时间:2011-06-22 13:28:08

标签: java multithreading

从多个线程调用方法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);
}

4 个答案:

答案 0 :(得分:8)

没有什么可以阻止另一个线程在containsKey / removeput之间放置一些值,因此在放置之前检查表是否已经包含一个键并不是真的“安全” (或者更确切地说,并没有“有意义”)。

你为什么不这样做

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);