0

У меня есть приложение OpenGL ES 2.0. В нем, у меня есть класс, который содержит массив другого типа объекта, например, так (это упрощенный для вопроса):Java: Защита объекта от доступа несколькими потоками

public class StoreList(){ 

thisList StoreItems[]; 

    public StoreList(int nuberOfItems){ 

     thisList = StoreItems[numberOfItems]; 

    } 

} 

Изначально я заполнить список, а затем в определенные моменты во время приложения (если пользователь находится в «магазине» сцены), это возможно для новых элементов, которые будут добавлены в список, так что, например, список может выглядеть примерно так:

Before    After inserting object 'Fish' into index 1 

Index 0 - Dog  Index 0 - Dog 
Index 1 - Fox  Index 1 - Fish 
Index 2 - Bird  Index 2 - Fox 
Index 3 - Snake Index 3 - Bird 
        Index 4 - Snake 

Теперь этот список итерация по разным причинам. Например, для рендеринга, для обновления их позиций и т. Д.

Проблема в том, что мое приложение использует 2 потока - поток GL Rendering и поток Main/UI.

Когда пользователь выполняет определенное действие, поток пользовательского интерфейса вызывает метод «insertObject», который вставляет дополнительный элемент, как описано выше. Однако поток рендеринга счастливо делает это, и если бы он отображал объект в индексе 1, в то же время вызывался «insertObject», тогда он начинает вызывать проблемы (каждый объект в списке имеет разное количество квадрантов OpenGL для рисования а число для рисования содержится в переменной в самом объекте), поэтому, если исходный объект в индексе 1 имел 5 квадрациклов, а новый объект имеет только 4, то он начинает пытаться рисовать пятый квад, и мы получаем все способ выпуска (например, индекс за пределами границ).

Метод рендеринга, метод updateLogic и методы onTouchEvent объявлены как синхронизированные, но я все еще получаю проблему.

Я не совсем уверен, как добиться обеспечения этого объекта (экземпляр StoreList и все внутри него и это массив thisList) можно обновлять только из одного потока за раз.

Вопросы, которые я видел, связанные с проблемами параллелизма, касались защиты метода от вызова несколькими потоками, а не объектами, поэтому я немного запутался.

Буду признателен за любые рекомендации.

+2

Возможно, ['CopyOnWriteArrayList'] (http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/CopyOnWriteArrayList.html) будет работать лучше для вас? – RealSkeptic

+1

Самый простой способ: защитить список с помощью ['Lock'] (https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/locks/Lock.html). Каждый метод, который хочет прочитать или записать список, должен сначала получить «Заблокировать». Немного сложнее: попробуйте использовать ['@ synchronized'] (https://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html). Если в '@ synchronized' не используются блокирующие конструкции (например,' wait() '), это должно выполнить задание. – Turing85

+0

Спасибо @ Turing85, Вы имеете в виду использование синхронизированного блока для всего кода, который будет читать/записывать из/в список? (Использование самого списка как объекта блокировки?) Мне просто интересно, могу ли я просто объявить любой метод, который читает/записывает в список как синхронизированный? Я только что сделал это, и до сих пор никаких сбоев (после примерно 30 тестов). Также я не уверен, что вы имеете в виду re '@synchronized'. Не могли бы вы привести пример? Спасибо за вашу помощь. – Zippy

ответ

0

Почему бы не использовать синхронизированный блок в StoreItems вместо синхронизации методов вставки/обновления. Синхронизированный блок гарантирует, что только один поток может выполнить блок кода вставки или любой другой блок кода (скажем, обновление), который синхронизируется на одном и том же объекте (т. Е. StoreItems) в любое время.

+1

Методы, отмеченные как синхронизированные, не блокируют метод, они блокируют экземпляр объекта в случае, если они являются экземплярами, и для класса, если они являются статическими.Таким образом, они уже блокируются на одном объекте. –

+0

Спасибо @RahulPrasad, есть ли какая-то причина, по которой вы предпочитаете синхронизированный блок за объявлением методов синхронизации? – Zippy

+1

Как отметил Марк в приведенном выше комментарии, при помощи методов синхронизации мы получим блокировку на полном экземпляре объекта, это означает, что ни один другой поток не может использовать какой-либо синхронизированный метод для этого экземпляра, тогда как любой синхронизированный метод запускается потоком , В предоставленном вами фрагменте кода и заданном вопросе акцент был сделан на члена класса «StoreItems»; поэтому я предложил использовать синхронизированный блок в StoreItems и приобрести блокировку вместо него в экземпляре StoreList. Кроме того, лучше использовать синхронизацию по частному объекту, а не по методу с точки зрения безопасности. –