我在一个groovy脚本中有一些代码,如果某个名称的图形不存在,我会创建一个新的实例。
if (!graphMap.contains(graphName)) {
newGraph = createGraph(graphName)
graphMap.put(graphName, newGraph)
}
问题是它并行运行并且createGraph()调用大约需要60秒,所以有时候我会创建2个图形实例,并且只将其中一个保存到我的地图中(因为它们都会看到map不包含名称然后创建它)。我的理解是我可以锁定地图以避免这个问题,如下所示:
synchronized(graphMap) {
if (!graphMap.contains(graphName)) {
newGraph = createGraph(graphName)
graphMap.put(graphName, newGraph)
}
}
但问题是创建图表可能需要一段时间,我希望能够同时为多个不同的名称创建图表。也就是说,如果我有3个并发请求为 foo , foo 和 bar 创建图表,我想创建 foo 和 bar 同时但不会创建第二个 foo 。我可以不在地图上同步,而是在特定的名称值上同步吗?
答案 0 :(得分:3)
快速解决方案是:
java.util.concurrent.ConcurrentHashMap
作为graphMap
的类型,以便您知道它可以处理并发添加(不同的密钥)。intern
ing it之后graphName
同步:graphName = graphName.intern();
synchronized(graphName) {
if (!graphMap.contains(graphName)) {
newGraph = createGraph(graphName)
graphMap.put(graphName, newGraph)
}
}
如果您有两个String
具有相同内容但位于不同String
个对象中,synchronized
无法正常工作,因为它会在不同对象上同步,也不会阻止另一个。
但是,当intern()
为String
提供某些内容时,它每次都会为这些内容返回相同的对象,因此在 对象上进行同步将正常工作
这允许您仅阻止特定graphName
的内容而不是整个graphMap
的内容,从而允许更多的并发性。它还可以防止任何浪费的工作,即为该键添加两次值。