Necesita la sincronización de prueba de tontos de ArrayList en un entorno multihilo

He estado en esto durante una semana haciendo mi investigación sobre cómo sincronizar correctamente un ArrayList.

Mi principal problema en pocas palabras es que tengo un ArrayList "maestro" de objetos. Pueden aparecer diferentes hilos y agregar / establecer / eliminar de esta lista. Necesito estar seguro de que cuando un hilo está iterando a través de ArrayList, otro no lo está cambiando.

Ahora he leído muchos artículos sobre la "mejor" forma de manejar esto:

usar collections.synchronizedlistutilizar CopyOnWriteArrayListusar bloques sincronizados () junto con colecciones.synchronizedlistusa Vector (muchas personas estan en contra de esto)

El uso de bloques sincronizados en cada iteración, agregar / establecer / eliminar bloque parece ser algo de lo que quiero, pero la gente ha dicho que hay muchos gastos generales.

Entonces empecé a jugar con CopyOnWriteArrayList (hago muchas más lecturas que escrituras para mi Master ArrayList). Esto está bien para la lectura, pero lo que muchos de los hilos del foro no mencionan es que los elementos no se pueden agregar, configurar o eliminar del iterador. Por ejemplo (una versión básica, pero imagínala en un entorno de subprocesos múltiples):

public static void main(String[] args) {

    class TestObject{
        private String s = "";
        public TestObject(String s){
            this.s = s;
        }

        public void setTheString(String s){
            this.s = s;
        }

        public String getTheString(){
            return s;
        }
    }

    CopyOnWriteArrayList<TestObject> list = new CopyOnWriteArrayList<TestObject>();
    list.add(new TestObject("A"));
    list.add(new TestObject("B"));
    list.add(new TestObject("C"));
    list.add(new TestObject("D"));
    list.add(new TestObject("E"));

    ListIterator<TestObject> litr = list.listIterator();

    while(litr.hasNext()){
      TestObject test = litr.next();
      if(test.getTheString().equals("B")){
         litr.set(new TestObject("TEST"));
      }
    }
}

la línea "litr.set (nuevo TestObject (" TEST "));" tiraría un

java.lang.UnsupportedOperationException

Y mirando la documentación de Java hay una línea específica que describe este comportamiento:

"Las operaciones de cambio de elementos en los iteradores en sí mismos (eliminar, establecer y agregar) no son compatibles. Estos métodos generan la excepción UnsupportedOperationException".

Entonces, estás obligado a modificar esa lista usando

list.set(litr.previousIndex(), new TestObject("TEST"));

Ahora, técnicamente, ¿no debería esto presentar un problema de sincronización? Si llegara otro subproceso al mismo tiempo, y diga, eliminar todos los elementos de la "lista", el iterador no lo vería, iría a establecer la "lista" en un índice dado y lanzaría una excepción porque el elemento en ese punto ya no existe Simplemente no entiendo el punto de CopyOnWriteArrayList si no puede agregar un elemento a través del propio iterador.

¿Me estoy perdiendo el punto con el uso de CopyOnWriteArrayList?

¿Envuelvo todos los iteradores que terminan teniendo que agregar / configurar / eliminar un elemento en un bloque sincronizado?

Este tiene que ser un problema común con subprocesos múltiples. Pensé que alguien habría hecho una clase que podría manejar todo esto sin preocuparse ...

Gracias de antemano por echar un vistazo a esto!

Respuestas a la pregunta(4)

Su respuesta a la pregunta