在单例中进行适当的同步

时间:2018-08-08 19:39:29

标签: java concurrency

我对同步有疑问。我有一个实例:

`

@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?我应该在这两种方法中都进行同步块吗?

2 个答案:

答案 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设为静态。