【问题标题】:Make proper synchronisation in singleton在单例中进行适当的同步
【发布时间】:2018-08-09 04:04:00
【问题描述】:

我有一个关于同步的问题。我有一个实例:

`

@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();
}

} 

问题是 - 在单例和许多线程调用服务的情况下如何进行正确的同步。似乎这两种方法都受到影响,有时无法为相同的字符串值计算/放入映射中的适当数据。 ConcurrentHashMap 会被 SynchronizedMap 取代吗?我应该在这两种方法中创建一个同步块吗?

【问题讨论】:

  • value 是第一种方法中的键和第二种方法中的值,这很容易引起误解。
  • 这确实是一个糟糕的重复,但对于 OP 问题来说真的很糟糕。
  • @davidxxx 我同意。重新打开。

标签: java concurrency


【解决方案1】:

您的put() 方法不是原子的。试试这个:

public String put(String value) {
    return cache.computeIfAbsent(value, v -> someRandomString());
}

【讨论】:

  • get() 方法也不是原子的。
  • @JohnBollinger 关于什么?
  • @JohnBollinger 但它不会破坏地图状态,因为使用了ConcurrentHashMapget() 中只能显示未更新的值。这是使用ConcurrentHashMap的主要原因。
【解决方案2】:

问题是 - 如何在以下情况下进行正确同步 单例和许多调用服务的线程。

您的同步范围需要涵盖整个逻辑操作,在这种情况下,它比内部Map 上的单个方法调用要广泛得多。因此,使用ConcurrentHashMap 或同步的Map 实现实际上并没有得到任何有用的东西,因为它们提供的关键区域的范围不够广泛。

对于您的特定示例,仅提供 put()get() 方法,最简单的方法是简单地声明每个方法 synchronized。在这种情况下,您可以在内部使用普通的HashMap。例如,

public synchronized String put(String key) {
    // ...
}

public synchronized String get(String key) {
    // ...
}

这假设确实只有一个类的实例。如果有多个,那么同步这些方法是不够的。然而,据推测,每个实例都需要自己的映射,因此也需要将cache 更改为实例变量,这将与同步一起解决问题。就个人而言,我一开始就不会将 cache 设为静态。

【讨论】:

  • 如果切换到HashMap,还需要同步get()
  • 是的,@k5_,您对“声明 each 方法 synchronized”的理解不同吗?但我已经更新以更好地强调这一点。
  • 抱歉错过了。
  • 这不可靠,只要cache 是静态的。虽然它可能不应该。
  • @shmosel,如果实例确实是单例,它将正常工作,正如 OP 所断言的那样。不过,您是对的,这一点值得关注。
猜你喜欢
  • 2019-11-11
  • 1970-01-01
  • 1970-01-01
  • 2012-06-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-16
  • 1970-01-01
相关资源
最近更新 更多