Java ArrayList - есть ли вызовы add() из одного потока, всегда читаемого из другого?
Thread 1: Call list.add()
Thread 1: Exits list.add()
Thread 2: Call list.get(list.size()-1)
У меня есть сценарий, где я могу гарантировать, что Thread 1
завершит вызов add() до Thread 2
, сделав вызов get(). Будет ли Thread 2
всегда видеть изменения, сделанные Thread 1
в этом случае? Или внутренние переменные ArrayList должны быть отмечены как изменчивые?
Изменить: Для тех, кому интересно, почему я могу это гарантировать. У меня есть последовательность событий с сервера, которые выглядят следующим образом:
Event A1
Event A2
Event A3
Event B
События отправляются последовательно одним потоком. Я хочу записать список всех событий A
, чтобы мой код выглядел следующим образом:
List<EventA> eventAList = new ArrayList<>();
connection.addListenerForEventAs(eventAList::add);
connection.waitForEventB();
//Here I am doing operations on the eventAList
Ответы
Ответ 1
Прежде всего, вам нужно будет убедиться, что происходит до того, как существует связь между вызовом add()
по потоку-1 и вызовом get()
по потоку-2. Завершение вызова и происходит до этого совершенно разные.
Если вы этого не сделаете, ваш код не будет потокобезопасным. Зачем?. Thread-1 может завершить вызов до add()
перед вызовом thread-2 get()
. Но какова гарантия того, что Thread-2 не сделает локальную копию списка (сохраните его)?. add()
метод не гарантирует, что произойдет раньше. Таким образом, нет никакой гарантии, что добавленная стоимость первого потока даже полностью написана и видна для потока-2.
Используйте CopyOnWriteArrayList
или Collections.SynchronizedList()
в многопоточной среде.
Ответ 2
Используйте Collections.SynchronizedList() в list
или ключевое слово, синхронизированное с выделенной реализацией для добавления для обеспечения безопасности потоков,
public synchronized void addItem(Item item) {
list.add(item);
}