2009-09-16 3 views
31

Я не уверен, что это правильный способ синхронизации моего ArrayList.Правильный способ синхронизации ArrayList в java

У меня есть ArrayListin_queue, который передается с функции registerInQueue.

ArrayList<Record> in_queue = null; 

public void registerInQueue(ArrayList in_queue) 
{ 
    this.in_queue = in_queue; 
} 

Теперь я пытаюсь синхронизировать его. Правильно ли это sychronizing мой объект in_queue?

List<Record> in_queue_list = Collections.synchronizedList(in_queue); 

synchronized (in_queue_list) { 
    while (in_queue_list.size() > 0) { 
     in_queue_list.remove(0); 
    } 
} 
+5

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

+0

Я буду помещать синхронизированный блок вокруг любой операции в очереди. Благодаря! – bob

ответ

41

Вы синхронизирующие дважды, что не имеет смысла, и, возможно, замедляет код: изменения в то время как итерация по списку нуждающемуся synchronnization в течение всей операции , которое вы делаете с synchronized (in_queue_list) Использование Collections.synchronizedList() является излишним в этом случае (он создает обертку, которая синхронизирует отдельные операции).

Однако, поскольку вы полностью опустошаете список, повторное удаление первого элемента является наихудшим возможным способом его выполнения. Для каждого элемента необходимо скопировать все следующие элементы, что делает это O (n^2) операция - ужасно медленная для больших списков.

Вместо этого просто позвоните clear() - не требуется итерации.

Edit: Если вам нужна синхронизация одного метода из Collections.synchronizedList() позже, то это правильный путь:

List<Record> in_queue_list = Collections.synchronizedList(in_queue); 
in_queue_list.clear(); // synchronized implicitly, 

Но во многих случаях, синхронизация одного метода недостаточно (например, для всей итерации или когда вы получаете значение, делайте вычисления на основе этого и замените его результатом). В этом случае вы должны использовать ручную синхронизацию в любом случае, так что Collections.synchronizedList() - это просто бесполезные дополнительные накладные расходы.

+7

Синхронизация дважды здесь не бессмысленно: она гарантирует, что пока цикл работает, никто другой не может изменить список. Однако использование функции clear() не является чем-то большим. :) – Bombe

+0

, поэтому я должен сделать что-то вроде: synchronized ((List) in_queue)? – bob

+0

Хорошо! Я фактически удалил немного кода, чтобы сделать его простым. У меня не будет проблемы с clear()/remove(). спасибо =] – bob

5

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

Однако есть далеко продвинутые параллельные очереди в Java, такие как ConcurrentLinkedQueue

8

Глядя на ваш пример, я думаю, что ArrayBlockingQueue (или его братьев и сестер) может пригодиться. Они ищут синхронизацию для вас, поэтому потоки могут записывать в очередь или заглядывать/принимать без дополнительной синхронизации с вашей стороны.

+0

Спасибо за предложение! Это то, что я пытаюсь сделать, но не уверен в ограничении размера моего массива. Я буду помнить об этом. ;) – bob

+0

Обратите внимание, что есть LinkedBlockingQueue. И вам необязательно вводить ограничения. –

+0

спасибо, я запомню это =] – bob

1

Давайте возьмем обычный список (реализуемый классом ArrayList) и сделаем его синхронизированным. Это показано в классе SynchronizedListExample. Мы передаем метод Collections.synchronizedList новый ArrayList of Strings. Метод возвращает синхронизированный список строк. // Вот SynchronizedArrayList класса

package com.mnas.technology.automation.utility; 
import java.util.ArrayList; 
import java.util.Collections; 
import java.util.Iterator; 
import java.util.List; 
import org.apache.log4j.Logger; 
/** 
* 
* @author manoj.kumar 
* @email [email protected] 
* 
*/ 
public class SynchronizedArrayList { 
    static Logger log = Logger.getLogger(SynchronizedArrayList.class.getName()); 
    public static void main(String[] args) {  
     List<String> synchronizedList = Collections.synchronizedList(new ArrayList<String>()); 
     synchronizedList.add("Aditya"); 
     synchronizedList.add("Siddharth"); 
     synchronizedList.add("Manoj"); 
     // when iterating over a synchronized list, we need to synchronize access to the synchronized list 
     synchronized (synchronizedList) { 
      Iterator<String> iterator = synchronizedList.iterator(); 
      while (iterator.hasNext()) { 
       log.info("Synchronized Array List Items: " + iterator.next()); 
      } 
     }  
    } 
} 

Обратите внимание, что при переборе по списку, этот доступ все еще сделан с помощью синхронизированного блока, который блокирует на объекте synchronizedList. Как правило, итерация по синхронизированной коллекции должна выполняться в синхронизированном блоке

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