我试着用 queue = new ConcurrentSkipListSet<Task>(Comparators.comparing(Task::priority))
作为具有唯一元素的并发优先级队列(请参阅此处的类似讨论),但我需要不时更改任务的优先级。
显然,当元素在集合中时改变它们的优先级就是打开一个蠕虫的罐头;幸运的是,我只需要在将它们从 queue
,然后再重新提交。更确切地说,我使用 pollFirst()
从 queue
,我可能需要在更新其优先级(优先级较低)后重新提交。
如果这是一个串行实现,那么当元素在集合之外时更改它们的优先级应该没有问题。
使用并发访问执行此更新的线程安全方式是什么?能保证吗 task = queue.pollFirst()
以前发生过 task.priorityUpdate()
,发生在 queue.add(task)
?
1条答案
按热度按时间j8ag8udp1#
所有并发集合都在元素put和元素get之间建立关系之前发生。
问题是,当他们在队列中时,您需要更改优先级,然后将他们取出并放回队列,因为这是唯一的方法;然后,一个并发线程可能同时放置同一个元素,这样您就失去了修改。在这种情况下,需要进一步同步。
但是,如果您要取出元素,更改它们的优先级,然后才评估是否应该将它们放回,那么在并发集合的保证足以确保正确性之前就会发生,您不需要做任何其他事情。
从
add()
至pollFirst()
有一个before关系,所以在线程中创建的对象调用add()
对线程调用可见pollFirst()
.从
pollFirst()
至add()
没有。但是,如果您更改了优先级,然后add()
对于同一线程,不需要进一步的内存约束。如果你以后打电话
pollFirst()
从另一个线程来看,在add()
以及pollFirst()
将保证在调用之前对对象进行更新add()
是可见的。