Я хочу вернуть немодифицируемое представление класса (поддерживающего набор элементов) внешним клиентам.Как синхронизировать немодифицируемые коллекции
Чтобы защитить одновременный доступ, мне нужно сначала обернуть коллекцию в синхронизированной оболочке, а затем поместить немодифицируемую оболочку вокруг версии, которую я верну в внешние потоки.
Итак, я написал следующий код и, к сожалению, бросает исключение ConcurrentModificationException. .
import java.util.*;
public class Test {
public static void main(String[] args) {
// assume c1 is private, nicely encapsulated in some class
final Collection col1 = Collections.synchronizedCollection(new ArrayList());
// this unmodifiable version is public
final Collection unmodcol1 = Collections.unmodifiableCollection(col1);
col1.add("a");
col1.add("b");
new Thread(new Runnable() {
public void run() {
while (true) {
// no way to synchronize on c1!
for (Iterator it = unmodcol1 .iterator(); it.hasNext(); it.next())
;
}
}
}).start();
while (true) {
col1 .add("c");
col1 .remove("c");
}
}
}
Так что мой вопрос Как синхронизировать нередактируемую коллекцию?
Чтобы добавить
Когда клиент, который получил коллекцию хочет перебрать его элементы
1) не обязательно знать, что это синхронизируется сбор и
2) даже если это так, он не может правильно синхронизировать мьютекс обертки синхронизации, чтобы перебирать его элементы. Штраф, как описано в Collections.synchronizedCollection, является недетерминированным поведением.
Из моего понимания Ввод немодифицируемой обертки в синхронизированную коллекцию не оставляет доступа к мьютексу, который должен удерживаться для правильной итерации.
Посмотрите, можете ли вы просто вернуть копию/моментальный снимок. делает вещи намного проще – ZhongYu
@ShowStopper, я не понимаю, что вы добавили в вопрос. 2. клиенту не нужно синхронизировать, JVM и Iterator делают это за него. – Gavriel
Collections.java:2030 общественный Итератор итератор() { return c.iterator(); // Должен быть вручную синхронизирован пользователем! }. Как вы можете видеть, ваша попытка не предотвратит CME, поскольку итератор не синхронизирован. Если вы хотите, чтобы итератор был синхронизирован, вам, возможно, придется обернуть его самостоятельно. Тем не менее, этот итератор будет недетерминированным, поскольку добавление элемента перед следующим() означает, что клиент не коснется его. –