Java — Какой наиболее эффективный способ синхронизации списка массивов?

#java #multithreading #data-structures #synchronization #arraylist

#java #многопоточность #структуры данных #синхронизация #список массивов

Вопрос:

В моей программе есть поток рендеринга OpenGL и поток модификации данных. Поток визуализации обращается к данным из множества списков массивов, в то время как поток модификации данных изменяет, удаляет и добавляет объекты в списки массивов. Потоки обновляются примерно 60 раз в секунду, и манипулирование списком массивов является узким местом программы. Я пробовал синхронизировать блоки (очень медленно), копировать списки массивов (довольно медленно) и создавать буферные списки массивов в потоке рендеринга (меньшее из трех зол). Какой «лучший» способ добиться максимальной эффективности от одновременных списков массивов?

Комментарии:

1. Вам нужно подробнее рассказать об алгоритме и топологии «группы списков массивов».

2. Рассматривали ли вы возможность использования ConcurrentHashMap or ConcurrentSkipListMap/Set ?

3. рассматривали ли вы пакет java.util.concurrent в качестве альтернативы блокам синхронизации?

4. К каким данным вы обращаетесь / изменяете? Возможно, существуют более эффективные структуры, чем списки массивов.

Ответ №1:

 List<YourObject> syncList = Collections.synchronizedList(yourList);
  

Комментарии:

1. Я чрезвычайно устал от этого решения. Прежде всего, коллекция должна быть синхронизирована вручную при использовании итератора, и могут возникнуть и другие проблемы. Я думаю, что это проблема с программной логикой.

2. Это дает вам общее решение «все или ничего», где, поскольку вопрос заключается в попытке достичь более высокой степени детализации блокировки

3. -1 Это вообще не отвечает на вопрос. Фактически, используя Collection. synchronized * всегда является самым дешевым, неэффективным и часто некорректным способом синхронизации в коллекции. Хотя иногда он может «выполнить задание», его полезно использовать только тогда, когда задание на самом деле не имеет значения.

Ответ №2:

Лучший механизм — выполнять свою работу в потоке GL и ставить операции в очередь, которые должны быть выполнены. Если к списку обращается только один поток, проблем нет.

Комментарии:

1. Почему лучше перенести программную логику в поток gl?

2. Вы ошибаетесь с состоянием GL. Все манипуляции с состоянием должны выполняться в потоке GL. Вот так просто.

3. На Android вам нужно получить экземпляр surface, а затем surface. queueEvent(new Runnable() { …. });

4. Или, возможно, что-то связанное с developer.android.com/reference/android/opengl /…

5. Похоже, у них есть два метода выполнения: один, при котором вы вставляете свой собственный код рендеринга в GLSurfaceView, который обрабатывается каждый кадр, и другой, при котором вы можете отправлять runnables для выполнения. Используйте первый метод для вашего общего кода, он более эффективен. Но для выполнения операций из других потоков, таких как изменение списков, «принадлежащих» потоку GL, вы бы опубликовали Runnable. Затем, когда все будет оценено, включая обновление GL и опубликованные runnables, ничто не будет выполняться одновременно с чем-либо еще. Это довольно просто.