Как правильно использовать синхронизированный? - PullRequest
2 голосов
/ 29 августа 2011

Этот кусок кода:

synchronized (mList) {
    if (mList.size() != 0) {
        int s = mList.size() - 1;
        for (int i = s; i > 0; i -= OFFSET) {
            mList.get(i).doDraw(canv);
        }
        getHead().drawHead(canv);
    }
}

Случайно выбрасывает AIOOBE. Из того, что я прочитал, синхронизированный должен предотвратить это, так что я делаю не так?

редактирует:

AIOOBE = Индекс массива за пределами исключения Код неполный, сокращен до того, что нужно. Но чтобы сделать вас счастливыми, OFFSET равен 4, и просто представьте, что в начале есть цикл for, добавляющий немного данных. И второй поток читает и / или изменяет список.

Редактировать 2:

Я заметил, что это происходит, когда список составляется и текущая игра заканчивается. Draw-поток не нарисовал все элементы, когда список очищается. Есть ли способ заставить игру ждать, опустив список, пока он не станет пустым?

Редактировать 3:

Я только что заметил, что не уверен, что это проблема многопоточности. Кажется, у меня есть только 2 потока, один для расчета и рисования и один для пользовательского ввода. Я должен рассмотреть это немного больше, чем я думал.

Ответы [ 4 ]

3 голосов
/ 29 августа 2011

Что вы делаете выглядит правильно ... но это все:

  1. Неважно, с каким объектом вы синхронизируете, не обязательно должен быть сам список.
  2. Важно то, что все потоки всегда синхронизируются на одном и том же объекте при доступе к общему ресурсу.
  3. Любой доступ к SWING (или другой графической библиотеке) должен происходить в AWT-Thread.

Для редактирования:

Я заметил, что это происходит, когда список составляется и текущая игра заканчивается. Draw-поток не нарисовал все элементы, когда список очищается. Есть ли способ заставить игру ждать, опустив список, пока он не станет пустым?

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

Опять же: Любой доступ к общему ресурсу должен быть как-то защищен. Кажется, вы используете synchronized именно здесь, а не там, где вы очищаете список.

0 голосов
/ 29 августа 2011

Я предлагаю использовать BlockingQueue , и я думаю, что вы ищете это решение также.Как вы можете это сделать?Это уже показано на примере в javadoc:)

 class Producer implements Runnable {
   private final BlockingQueue queue;
   Producer(BlockingQueue q) { queue = q; }
   public void run() {
     try {
       while (true) { queue.put(produce()); }
     } catch (InterruptedException ex) { ... handle ...}
   }
   Object produce() { ... }
 }

 class Consumer implements Runnable {
   private final BlockingQueue queue;
   Consumer(BlockingQueue q) { queue = q; }
   public void run() {
     try {
       while (true) { consume(queue.take()); }
     } catch (InterruptedException ex) { ... handle ...}
   }
   void consume(Object x) { ... }
 }

 class Setup {
   void main() {
     BlockingQueue q = new SomeQueueImplementation();
     Producer p = new Producer(q);
     Consumer c1 = new Consumer(q);
     Consumer c2 = new Consumer(q);
     new Thread(p).start();
     new Thread(c1).start();
     new Thread(c2).start();
   }
 }

Выгода для вас - вам не нужно беспокоиться о синхронизации ваших mList.BlockingQueue предлагает 10 специальных методов.Вы можете проверить это в документе.Немного от javadoc:

Методы BlockingQueue представлены в четырех формах с различными способами обработки операций, которые не могут быть выполнены немедленно, но могут быть выполнены в какой-то момент в будущем: один вызывает исключение, второйвозвращает специальное значение (либо ноль, либо false, в зависимости от операции), третий блокирует текущий поток на неопределенный срок до тех пор, пока операция не может быть успешной, а четвертый блокирует только заданный максимальный срок, прежде чем отказаться.

Чтобы быть в безопасности: у меня нет опыта работы с Android.Поэтому не уверен, разрешены ли все пакеты Java в Android.Но, по крайней мере, это должно быть: -S, я желаю.

0 голосов
/ 29 августа 2011

Безопасное решение - позволить одному потоку создавать объекты, добавлять и удалять их из списка после начала игры.

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

Мое решение, которое теперь стабильно и быстро (с тех пор никогда не было AIOOBE), состоит в том, чтобы заставить поток пользовательского интерфейса информировать игровой поток о создании или манипулировании объектом, устанавливая флаг и координаты касания в постоянных переменных.

Так как игровой поток зацикливается примерно 60 раз в секунду, этого оказалось достаточно, чтобы взять сообщение из потока пользовательского интерфейса и что-то сделать.

Это очень простое решение, и оно прекрасно работает!

0 голосов
/ 29 августа 2011

Вы получаете Index вне Bounds Exception, потому что есть 2 потока, которые работают со списком и делают это неправильно.Вы должны были синхронизироваться на другом уровне, чтобы ни один другой поток не мог перебрать список, пока другой поток его модифицирует!Только в потоке одновременно должен «работать» со списком.

Я полагаю, у вас следующая ситуация:

// фрагмент кода, который добавляет некоторый элемент в список

synchronized(mList){
    mList.add(1, drawableElem);
    ...
}

и

// код, который повторяет ваш список (ваш код упрощен)

synchronized (mList) {
    if (mList.size() != 0) {
        int s = mList.size() - 1;
        for (int i = s; i > 0; i -= OFFSET) {
            mList.get(i).doDraw(canv);
        }
        getHead().drawHead(canv);
    }
}

По отдельности фрагменты кода выглядят хорошо.Они шов нить безопасны.Но 2 отдельных поточно-ориентированных фрагмента кода могут быть поточно-ориентированными на более высоком уровне!Просто вы бы сделали следующее:

Vector v = new Vector();
if(v.length() == 0){    v.length() itself is thread safe!
  v.add("elem");        v.add() itself is also thread safe individually!
}

НО составной операции НЕ БУДЕТ!

С уважением, Тибериу

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...