Правильный способ синхронизации ArrayList в java
-
07-07-2019 - |
Вопрос
Я не уверен, что это правильный способ синхронизировать мой 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);
}
}
Решение
Вы синхронизируете дважды, что бессмысленно и, возможно, замедляет работу кода:изменения при переборе списка требуют синхронизации всей операции, которую вы выполняете с помощью synchronized (in_queue_list)
Используя Collections.synchronizedList()
является излишним в этом случае (он создает оболочку, которая синхронизирует отдельные операции).
Однако, поскольку вы полностью очищаете список, повторное удаление первого элемента - наихудший из возможных способов сделать это, так как для каждого элемента все последующие элементы должны быть скопированы, что делает эту операцию O (n ^ 2) ужасно медленной для больших списков.
Вместо этого просто позвоните clear()
- никаких повторений не требуется.
Редактировать:
Если вам нужна однометодная синхронизация Collections.synchronizedList()
позже, значит, это правильный путь:
List<Record> in_queue_list = Collections.synchronizedList(in_queue);
in_queue_list.clear(); // synchronized implicitly,
Но во многих случаях синхронизация одним методом недостаточна (например,для всей итерации или когда вы получаете значение, выполните вычисления на его основе и замените его результатом).В этом случае вам все равно придется использовать ручную синхронизацию, так что Collections.synchronizedList()
это просто бесполезные дополнительные накладные расходы.
Другие советы
Глядя на ваш пример, я думаю, что ArrayBlockingQueue (или его братья и сестры) могут быть полезны. Они следят за синхронизацией для вас, поэтому потоки могут писать в очередь или просматривать / извлекать данные без дополнительной синхронизации с вашей стороны.
Это правильно и задокументировано.
http : //java.sun.com/javase/6/docs/api/java/util/Collections.html#synchronizedList (java.util.List) р>
Однако, чтобы очистить список, просто вызовите List.clear () . р>
Да, это правильный путь, но синхронизированный блок необходим, если вы хотите, чтобы все удаления вместе были безопасными - если очередь не пуста, удаление не допускается. Я предполагаю, что вам нужны безопасные операции очереди и удаления из очереди, чтобы вы могли удалить синхронизированный блок.
Однако в Java существуют далеко идущие параллельные очереди, такие как ConcurrentLinkedQueue
Давайте возьмем обычный список (реализованный классом 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. В общем, перебор синхронизированной коллекции должен выполняться в синхронизированном блоке