2013-05-20 2 views
1

У меня есть два потока, которым необходимо получить доступ к переменной экземпляра ArrayList<short[]>.Как остановить столкновение двух потоков при доступе к java ArrayList?

Один поток будет асинхронно добавить short[] элементы в список с помощью обратного вызова, когда новые данные прибыли: void dataChanged(short[] theData)

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

Как я могу настроить это для защиты от столкновений между двумя потоками?

Это надуманный пример кода в настоящее время бросает java.util.ConcurrentModificationException

//instance vairbales 
private ArrayList<short[]> list = new ArrayList<short[]>(); 

//asynchronous callback happening on the thread that adds the data to the list 
void dataChanged(short[] theData) { 
    list.add(theData); 
} 

//thread that iterates over the list and processes the current data it contains 
Thread thread = new Thread(new Runnable() { 
    @Override 
    public void run() { 

     while (true) { 

      for(short[] item : list) { 
       //process the data 
      } 

      //clear the list to discared of data which has been processed. 
      list.clear(); 

      try { 
       Thread.sleep(1000); 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 
     } 
    } 
}); 

ответ

4

Самый простой способ изменить тип списка на thread safe list implementation:

private List<short[]> list = new CopyOnWriteArrayList<short[]>(); 

Обратите внимание, что этот тип списка не очень эффективен, если вы много мутируете (добавьте/удалите), но если это сработает для вас, это простое решение.

Если вам нужно больше эффективности, вы можете использовать synchronized list вместо:

private List<short[]> list = Collections.synchronizedList(new ArrayList<short[]>()); 

Но вам нужно будет синхронизировать для итерация:

synchronized(list) { 
    for(short[] item : list) { 
     //process the data 
    } 
} 

EDIT: предложение использовать BlockingQueue, вероятно, лучше но вам потребуется больше изменений в вашем коде.

7

Возможно, вы захотите использовать очередь producer consumer вместо ArrayBlockingQueue или аналогичную параллельную коллекцию.

Проблема производителя-потребителя (также известная как проблема с ограниченным буфером) является классическим примером проблемы с несколькими процессами синхронизации. Проблема описывает два процесса - производителя и потребителя, которые имеют общий буфер фиксированного размера, используемый в качестве очереди. Задача производителя состоит в том, чтобы сгенерировать фрагмент данных, поместить его в буфер и начать снова. В то же время потребитель потребляет данные (т. Е. Удаляет их из буфера) по одной штуке за раз. Проблема состоит в том, чтобы убедиться, что производитель не будет пытаться добавлять данные в буфер, если он заполнен, и что потребитель не будет пытаться удалить данные из пустого буфера.

Один поток offer сек short[] s, а другой take() S их.

+0

+1 Это путь! – assylias

+0

+1 правильный способ разработки решения – Stephan

0

Взгляните на поддержку синхронизации Java.

This page обложки, делающие группу операторов синхронизированными по заданному объекту. То есть: только один поток может выполнять любые разделы, синхронизированные на этом объекте, все остальные должны ждать.

0

Вы можете использовать блоки synchronized, но я думаю, что лучшим решением является не передавать изменчивые данные между потоками вообще.

Создайте каждую нить, чтобы писать в своем собственном пространстве, и собирайте и суммируйте результаты, когда рабочие закончены.

Смежные вопросы