Давайте начнем с самого начала. Я прочел ваш код так, что логика вашего компаратора c исправна. (Я бы не использовал нулевые значения Task
и DateTime
, но это не относится к вашей проблеме.)
Другая причина, которая может вызвать это исключение, - это если метод compare
дает несогласованные результаты, потому что Task
объекты меняются. Действительно, похоже, что это семантически значимо для (по крайней мере) количества попыток измениться. Если есть другой поток, который изменяет Task
поля, которые могут повлиять на порядок ... в то время как текущий поток сортирует ..., это может IllegalArgumentException
.
(Часть договора сравнения заключается в том, что попарное упорядочение не изменяется при сортировке коллекции.)
Затем вы говорите следующее:
Я использую ImmutableSet.copyOf
, чтобы скопировать список перед сортировкой, и я делаю это под блокировкой чтения в java.util.concurrent.locks.ReadWriteLock
.
Копирование коллекции не приводит к копированию элементов коллекции. Это мелкая копия. Таким образом, вы получите две коллекции, которые содержат одинаковые объекты. Если другой поток мутирует какой-либо из объектов (например, путем увеличения числа повторов), это может изменить порядок объектов.
Блокировка гарантирует, что у вас есть согласованная копия, но проблема не в этом.
Какое решение? Я могу вспомнить пару:
Вы можете заблокировать что-либо, чтобы заблокировать все обновления коллекций И объекты-элементы во время копирования и сортировки.
Вы можете глубоко скопировать коллекцию; т.е. создать новую коллекцию, содержащую копии элементов исходной коллекции.
Вы можете создавать легковесные объекты, которые содержат снимки полей Task
соответствующих объектов на сортировку; например,
public class Key implements Comparable<Key> {
private int retries;
private DateTime creation;
private DateTime load;
private Task task;
public Key(Task task) {
this.task = task;
this.retries = task.getRetryCount();
...
}
public int compareTo(Key other) {
// compare using retries, creation, load
}
}
. Это дает потенциальные преимущества, поскольку вы копируете меньше информации, и вы можете go из отсортированной коллекции Key
объектов в исходные Task
объекты.
Обратите внимание, что все эти альтернативы медленнее, чем то, что вы делаете в настоящее время. Я не думаю, что есть способ избежать этого.