2012-07-10 49 views
0

我不理解下面的代码片断如何能够线程安全。使用线程安全集合的多个线程

class MapUser { 
    Map<String,Integer> map = new ConcurrentHashMap<String,Integer> 

    public void addToMap(String str, Integer val){ 
     if(checkMagicString(str)){ 
      map.put(str,val); 
     } 
    } 

    private boolean checkMagicString(String str){ 
     //some logic to check Magic 
     //this logic involved operation on the String parameter str i.e. subString,toCharArray etc 
    } 
} 

注意方法addToMap被多个线程同时调用。我想确保线程的安全性。通过使用ConcurrentHashMap,我可以确保线程安全地将值添加到它。

但是我不明白如何方法checkMagicString(String str)可以保持线程安全?唯一的办法是让它同步吗?或者应该使调用方法addToMap同步? 请注意,我没有访问checkMagicString方法内的地图。

+2

我假设你正在访问'checkMagicString'内的'map'?如果没有,那么你很好。如果你是那么请编辑你的帖子以表明这一点。 – Gray 2012-07-10 16:58:50

回答

2

即使你做checkMagicString原子,它不会使该序列

if(checkMagicString(str)){ 
    map.put(str,val); 
} 

原子,因为一个线程可以在if检查和map.put调用之间被中断,因此你可能最终有两个线程插入相同的字符串。您需要锁定整个序列以确保安全。

编辑:如果上述是可接受的行为(即,两个线程插入相同的密钥和覆盖值)和checkMagicString不会在共享状态操作然后代码是细因为它是。

+0

这真的取决于checkMagicString在做什么。只要它不访问映射,这2个操作就不必是原子来维护线程安全。 – assylias 2012-07-10 17:02:19

+0

@assylias:这两个操作不,但顺序应该是,因为我认为他不想让两个线程放置相同的字符串。 – Tudor 2012-07-10 17:03:00

+0

你的意思是使用synchronized的addToMap方法吗?如果这是必需的,那么多线程的好处在哪? – Eager 2012-07-10 17:03:49

0

如果你想要的是一个原子操作的情况下做到这样是为了确保checkMagicStr原子,并且还使用了地图上的原子操作的最好的事情:

boolean done = false; 
while(!done) { 
    Integer oldVal = map.get(str); 
    if (checkMagicStr(str) { 
    if (oldVal != null) { 
     done = value == map.replace(str, val, oldVal); // otherwise try again... 
    } else { 
     done = null == map.putIfAbsent(str, val); // otherwise try again... 
    } 
    } else { 
    done = true; // there's nothing to do... 
    } 
} 

你可能想在while循环中有一个限制,并且如果它被触发就会抛出异常,因为这可能会在高度并发的系统上永远运行。从你的问题中不清楚为什么这些都是必要的,尽管如此,B/C你所拥有的将是“线程安全的”,但也许这会有所帮助。