Какую коллекцию Java следует использовать, если у меня много объектов с медленно меняющимися ключами?
В основном у меня есть один ArrayList, в котором есть все объекты, требующие сортировки.Этот ArrayList иногда изменяется другим потоком.Чтобы перебрать его, я записал ArrayList в другой ArrayList с помощью clear и затем addAll до сих пор, но теперь я понял, что это также может вызвать исключение ConcurrentModificationException, поэтому я хочу изменить это.
Эта новая коллекция (в настоящее время ArrayList), который я использую для итерации, должен быть отсортирован с помощью специального компаратора.Проблема в том, что, прежде чем я сделаю следующую копию оригинала, ключи будут изменены, и мне придется сортировать их несколько раз.Порядок для этих сортов почти всегда правильный.Сортировка вставки здесь может быть хорошей.
Большой вопрос сейчас:
- Должен ли я использовать TreeSet и вызывать на нем Collections.sort при изменении порядка
- Использую ли якакой-то List (какой? ArrayList? LinkedList?) и вызов Collections.sort при изменении порядка
Я думаю, что правильный ответ на этот вопрос можно дать, только если учесть, что мне нужно скопироватьсначала другую несортированную коллекцию (ArrayList, но не обязательно) и делайте это, пока данные в коллекции изменяются другим потоком.
Мои мысли по поводу решения следующие:
- Пусть вторая коллекция будет ArrayList и обновлять ее всегда с Collections.copy (сначала нужно сделать правильный размер, но обычно это должен быть правильный размер уже в моем сценарии (я понимаю, что это не атомарно и может вызвать проблемы)), затемзвоните Collections.sort на него так часто, как я хочу.Может быть, реализовать алгоритм сортировки вставкой для каждой сортировки после начальной сортировки, потому что он должен быть быстрее.
- Как-нибудь использовать TreeSet для второй коллекции.Проблема в том, что я не знаю, как бы я перебрал исходный потокобезопасный, чтобы добавить все элементы оттуда.Также я не знаю, как эффективно сортировать Set после этой инициализации.Я видел, как кто-то использует Collections.sort, но я не знаю об эффективности там.Также помните, что он почти отсортирован.
Что нужно иметь в виду, мне нужно только перебирать как исходную, так и рабочую копию Collection, индексация не требуется.
Я сделал некоторый Java-код, чтобы показать проблему сейчас:
public static List<FloatWrapper> pending_additions = Collections.synchronizedList(new ArrayList<>());
public static List<FloatWrapper> pending_removals = Collections.synchronizedList(new ArrayList<>());
public static List<FloatWrapper> list = new ArrayList<>();
public static Random rnd = new Random();
public static void main(String[] args) {
// initialize array
for (int i = 0; i < 1000; i++) {
list.add(new FloatWrapper(i));
}
// the main loop (runs basically infinitly)
for (int runs_infinitly = 0; runs_infinitly < 100; runs_infinitly++) {
// apply pending changes
synchronized (pending_additions) {
list.addAll(pending_additions);
pending_additions.clear();
}
synchronized (pending_removals) {
list.removeAll(pending_removals);
pending_removals.clear();
}
// doing my stuff
for (int i = 0; i < 5; i++) {
// sort array with quicksort I believe, which is not the fastest
// for this scenario usually, except for the start when its completly unsorted
System.out.println("sorting");
Collections.sort(list);
// iterate very often doing different things
for (int j = 0; j < 1; j++) {
for (FloatWrapper num : list) {
// do something with num
System.out.print(num.number + " ");
}
System.out.println();
}
System.out.println("changing keys");
// change the values that are used for sorting
for (FloatWrapper num : list) {
num.number += (rnd.nextFloat() - 0.5f) * 0.2f;
}
}
}
}
public static class FloatWrapper implements Comparable<FloatWrapper> {
public float number;
public FloatWrapper(float number) {
this.number = number;
}
public int compareTo(FloatWrapper arg0) {
return Float.compare(number, arg0.number);
}
}
Массивы pending_additions и pending_removals - единственные, написанные из другого потока.Это мое улучшение с тех пор, как я написал этот пост, поэтому не нужно копировать и восстанавливать весь список.
Мой вопрос остается в силе, должен ли я использовать TreeSet для повышения производительности, должен ли я сделать что-то другое?По сути, я не знаю, как эффективно сортировать TreeSet.Я мог даже предположить, что ArrayList с Collection.sort () более эффективен, но я не знаю.Может кто-нибудь объяснить это.
Также я использую собственный компаратор, в котором есть даже немного математики, так что здесь очень удобно оптимизировать процесс сортировки