3

我正在尝试使用

queue = new ConcurrentSkipListSet<Task>(Comparators.comparing(Task::priority))

作为具有唯一元素的并发优先级队列(请参阅此处的类似讨论),但我需要不时更改任务的优先级。

显然,改变元素在集合中的优先级就像打开一罐蠕虫;幸运的是,我只需要在将它们从queue中删除之后以及重新提交它们之前更改它们的优先级。更准确地说,我用来pollFirst()从 中弹出一个元素queue,我可能需要在更新其优先级(具有较低优先级)后重新提交。

如果这是一个串行实现,那么在元素位于集合之外时更改元素的优先级应该没有问题。

使用并发访问进行此更新的线程安全方式是什么? 是否足以保证

task = queue.pollFirst()以前发生过task.priorityUpdate(),以前发生过queue.add(task)

4

1 回答 1

1

所有并发集合都在元素 put 和 element get 之间建立发生前的关系。

问题是,如果您需要在他们在队列中时更改优先级,然后将它们取出并放回,因为这是唯一的方法;然后,并发线程可能会同时放置相同的元素,然后您将丢失您的修改。在这种情况下,将需要进一步同步。

但是,如果您要取出元素,更改它们的优先级,然后才评估是否应该将它们放回原处,那么并发集合的发生前保证就足以确保正确性,您无需做任何其他事情。

From add()topollFirst()存在happens-before关系,因此线程调用中创建的对象对线程调用add()可见pollFirst()

pollFirst()那里add()没有。但是,如果您更改优先级然后add()从同一个线程调用,则不需要进一步的内存限制。
如果您稍后从另一个线程调用,则和pollFirst()之间的发生之前的关系将保证调用之前对对象的更新是可见的。add()pollFirst()add()

于 2020-12-27T11:50:45.443 回答