【问题标题】:Update map/set and check size atomically自动更新地图/设置并检查大小
【发布时间】:2018-09-05 13:09:04
【问题描述】:

我有以下方法:

private static HashSet<Integer> ids = new HashSet<>();  
public static void someMethod(SomeObject o) {  
  // some code  

 ids.add(o.getId());   
 if(ids.size() > 10) {  
   // do something  
 }  
 else {  
  // do something else  
 }  
}  

使这个方法线程安全的一个简单方法是添加关键字synchronized
我想知道是否已经有一些更合适的方法可以在地图/集合中添加项目并自动检查大小

【问题讨论】:

  • 不知道除了使用synchronized关键字之外的任何其他可能性。使用有什么问题吗?
  • @AnarchoEnte:我只是想知道是否还有其他方法可以通过ConcurrentHashMap 和类似方法
  • 在这篇文章之后,由于ids.size() 调用,您无法使用ConcurrentHashMap 来实现上述代码的全线程安全。 stackoverflow.com/questions/25998536/…
  • ConcurrentHashMap 不是解决方案,它将返回大小的估计值。但是,如果您在此处同步整个方法,您将做的不仅仅是在地图/集合中添加一个项目并自动检查大小,您还可以执行do somethingdo something else - 你明白吗?
  • @Eugene:是的,但是这些部分对性能的影响很小。我想知道是否有一种惯用的 java 方式来解决这个问题

标签: java multithreading concurrency thread-safety hashset


【解决方案1】:

这样的事情不存在,正如 cmets 中所说,甚至 ConcurrentHashMap 都不会帮助你。

在这里要非常小心,不要落入这里的 check-than-act 反模式的陷阱。所以例如不做:

 Set<Integer> syncIds = Collections.synchronizedSet(ids);
 syncIds.add(o.getId())  
 if(ids.size() > 10) {....}

作为单独的操作,它们确实是线程安全的,但作为复合操作,它们不是。

请记住,由于您在锁下更新了 HashSet,因此在读取它时,必须在同一锁下完成 ,这就是 之前发生的方式 em> 有效。所以如果你暴露一个方法:

public Set<Integer> getIds(){
    return ids;
}

为了使其正常工作并且您不会遇到意外,此方法也需要同步。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-10
    • 2014-12-31
    相关资源
    最近更新 更多