Правильный способ синхронизации ArrayList в Java - PullRequest
33 голосов
/ 16 сентября 2009

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

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

ArrayList<Record> in_queue = null;

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

Теперь я пытаюсь синхронизировать это. Правильно ли синхронизирует мой 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 ]

44 голосов
/ 16 сентября 2009

Вы синхронизируете дважды, что бессмысленно и, возможно, замедляет код: изменения при переборе по списку требуют синхронизации всей операции, которую вы делаете с 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() - это просто бесполезные дополнительные затраты.

8 голосов
/ 16 сентября 2009

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

5 голосов
/ 16 сентября 2009

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

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

5 голосов
/ 16 сентября 2009

Это правильно и задокументировано:

http://java.sun.com/javase/6/docs/api/java/util/Collections.html#synchronizedList(java.util.List)

Однако, чтобы очистить список, просто позвоните List.clear () .

1 голос
/ 07 января 2015

Давайте возьмем обычный список (реализованный классом ArrayList) и сделаем его синхронизированным. Это показано в классе SynchronizedListExample. Мы передаем методу Collections.synchronizedList новый ArrayList из строк. Метод возвращает синхронизированный список строк. // Вот класс 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 kumarmanoj.mtech@gmail.com
* 
*/
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. В общем, перебор синхронизированной коллекции должен выполняться в синхронизированном блоке

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