Синхронизированный список Java для цикла

Документация по synchronizedList утверждает, что

Обязательно, чтобы пользователь вручную выполнял синхронизацию по возвращенному списку при итерации по нему:

List list = Collections.synchronizedList(new ArrayList());
...
synchronized(list) {
    Iterator i = list.iterator(); // Must be in synchronized block
    while (i.hasNext())
    foo(i.next());
}

Несоблюдение этого совета может привести к недетерминированному поведению.

Это кажется довольно ясным, но я просто хотел подтвердить, что для каждого цикла запрещено. Например, я не могу сделать что-то вроде следующего правильно?

List<MyType> list = Collections.synchronizedList(new ArrayList(<MyType>));
...
synchronized(list){
    for(MyType m : list){
        foo(m);
        m.doSomething();
    }
}

Ответы

Ответ 1

Да, вы можете - ваш расширенный цикл for в основном такой же, как ваш код, который явно использует итератор. Он сводится к одному и тому же коду - он просто вызывает iterator(), а затем чередует вызовы next() и hasNext().

Ответ 2

Вы можете это сделать. Цикл foreach компилирует (почти) тот же байт-код, что и цикл while. Клавиши:

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

Ответ 3

Конечно, вы можете, единственная проблема, которую я вижу здесь, - это проблема производительности, если ваш метод dosomething() или foo(m) будет дорогостоящим для выполнения, у вас будет стоимость исполнения. Размер вашей коллекции также очень важен для учета во время цикла в синхронизированном блоке из-за того, что когда поток получает блокировку, а в синхронизированном блоке цикл в огромной коллекции заставит другие потоки ждать.