java - ConcurrentSkipListMap 如何使删除和添加调用原子化

标签 java multithreading java-8 java.util.concurrent

我有 N 个添加值的线程和一个删除线程。我正在考虑如何同步添加到现有值列表和删除列表的最佳方法。

我猜下面的情况是可能的:

 thread 1 checked condition containsKey, and entered in else block
 thread 2 removed the value
 thread 1 try to add value to existing list, and get returns null

我认为我可以使用的唯一方法是按映射值同步,在我们的例子中是添加和删除时的列表

    private ConcurrentSkipListMap<LocalDateTime, List<Task>> tasks = new ConcurrentSkipListMap<>();

    //Thread1,3...N
    public void add(LocalDateTime time, Task task) {
        if (!tasks.containsKey(time)) {
            tasks.computeIfAbsent(time, k -> createValue(task));
        } else {
             //potentially should be synced
            tasks.get(time).add(task);
        }
    }
    private List<Task> createValue(Task val) {
        return new ArrayList<>(Arrays.asList(val));
    }

    //thread 2
   public void remove()
    while(true){
        Map.Entry<LocalDateTime, List<Task>> keyVal = tasks.firstEntry();
        if (isSomeCondition(keyVal)) {
            tasks.remove(keyVal.getKey());
            for (Task t : keyVal.getValue()) {
                //do task processing
            }
        }
    }
   }

最佳答案

关于 add 部分,您真的倾向于使用 merge,但是文档对此非常清楚 - 说它是不保证原子发生。

我会用 merge 替换您的 add,但是处于锁定状态

SomeLock lock ... 
public void add(LocalDateTime time, Task task) {
    lock.lock();
    tasks.merge...
    lock.unlock();
}

remove 方法也是如此。但是,如果您在锁定状态下做事,则首先不需要 ConcurrentSkipListMap

另一方面,如果您可以更改为 ConcurrentHashMap - 它具有例如原子性的 merge

关于java - ConcurrentSkipListMap 如何使删除和添加调用原子化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46308086/

相关文章:

java-8 - Java8 : Filter and map on same method output

java - ZoneOffset.UTC 和 ZoneId.of ("UTC"有什么区别?

python - 线程提示是串行运行,而不是并行运行?

java - 当它是回文时,为什么这个反转的 StringBuilder 不等于原来的 String?

java - 在Java中计算生成的随机数中的最大和最小数

java - mockito - 检查条件是否通过并调用不返回任何内容的方法

java - 线程需要等待列表更新

c++ - 如何实现不溢出的原子引用计数器?

java - 在同一个流上重复 forEach() - 为什么不可能?

java - this(<params>) 作为构造函数中的快捷方式?