我对同步有疑问。我有一个实例:
`
@Service
public class MyService {
//if singleton - should this map be static?
private static Map<String, String> cache = new ConcurrentHashMap<String, String>();
public String put(String value) {
if (!cache.containsKey(value)) {
String newValue = someRandomString();
cache.put(value, newValue);
return newValue;
}
return cache.get(value);
}
public String get(String value) {
return cache.entrySet().stream()
.filter(e -> e.getValue().equals(value))
.map(Map.Entry::getKey)
.findFirst().get();
}
}
问题是-在单例和许多线程调用服务的情况下如何进行适当的同步。似乎这两种方法都受影响,并且有时对于相同的String值,无法计算/将适当的数据放入映射中。是否将ConcurrentHashMap替换为SynchronizedMap?我应该在这两种方法中都进行同步块吗?
答案 0 :(得分:1)
您的put()
方法不是原子的。尝试以下方法:
public String put(String value) {
return cache.computeIfAbsent(value, v -> someRandomString());
}
答案 1 :(得分:0)
问题是-在发生以下情况时如何进行适当的同步 单例和许多调用该服务的线程。
您的同步范围需要覆盖整个逻辑操作,在这种情况下,这些操作比内部Map
上的单个方法调用要宽得多。因此,使用ConcurrentHashMap
或同步的Map
实现并不会带来任何有用的帮助,因为它们提供的关键区域的范围不够广泛。
对于您的特定示例,仅提供put()
和get()
方法,最简单的方法是简单地声明每个方法synchronized
。在这种情况下,您可以在内部使用普通的HashMap
。例如,
public synchronized String put(String key) {
// ...
}
public synchronized String get(String key) {
// ...
}
这假设确实只有该类的一个实例。如果不止一个,那么同步方法是不够的。但是,大概每个实例都想要自己的映射,因此也需要将cache
更改为实例变量,这将与同步一起解决问题。就个人而言,我一开始就不会将cache
设为静态。