2010-09-28 34 views
12

he creado arrayList sincronizada como estocómo crear sincronizada ArrayList

import java.text.SimpleDateFormat; 
import java.util.*; 


class HelloThread 
{ 

int i=1; 
List arrayList; 
    public void go() 
    { 
arrayList=Collections.synchronizedList(new ArrayList()); 
Thread thread1=new Thread(new Runnable() { 

    public void run() { 
    while(i<=10) 
    { 
    arrayList.add(i); 
    i++; 
    } 
    } 
}); 
thread1.start(); 
Thread thred2=new Thread(new Runnable() { 
    public void run() { 
    while(true) 
    { 
    Iterator it=arrayList.iterator(); 
     while(it.hasNext()) 
     { 
     System.out.println(it.next()); 
     } 
    } 
    } 
}); 
thred2.start(); 
    } 
} 

public class test 
{ 
    public static void main(String[] args) 
    { 
    HelloThread hello=new HelloThread(); 
    hello.go(); 
    } 
} 

pero conseguir una excepción como ésta

Excepción en hilo java.util.ConcurrentModificationException "Tema-1"

nada malo en mi enfoque?

Respuesta

23

Iterator de synchronizedList no es (y no se puede) a sincronizar, debe sincronizar manualmente en la lista, mientras que la iteración (ver javadoc):

synchronized(arrayList) { 
    Iterator it=arrayList.iterator(); 
    while(it.hasNext()) { 
     System.out.println(it.next()); 
    } 
} 

Otro enfoque es utilizar un CopyOnWriteArrayList en lugar de Collections.synchronizedList() . Implementa una semántica de copia sobre escritura y, por lo tanto, no requiere sincronización.

0

No puede modificar una colección que está iterando. Puede solucionar esto accediendo a las entradas de la matriz por índice, no a través de un iterador. Puedo proporcionar más consejos si me dices el problema que estás tratando de resolver con este código.

+0

puedo conseguir el punto de que no puedo utilizar para acceder al repetidor arrayList sincronizada. – Lalchand

2

Como dijo Spike, no puede modificar una colección mientras la itera. Sin embargo, creo que la solución es bloquear la lista mientras se itera.

class HelloThread 
{ 

int i=1; 
List arrayList; 
    public void go() 
    { 
arrayList=Collections.synchronizedList(new ArrayList()); 
Thread thread1=new Thread(new Runnable() { 

    public void run() { 
    while(i<=10) 
    { 
synchronized(someLock) { 
    arrayList.add(i); 
} 
    i++; 
    } 
    } 
}); 
thread1.start(); 
Thread thred2=new Thread(new Runnable() { 
    public void run() { 
    while(true) 
    { 
synchronized(someLock) { 
    Iterator it=arrayList.iterator(); 
     while(it.hasNext()) 
     { 
     System.out.println(it.next()); 
     } 
} 
    } 
    } 
}); 
thred2.start(); 
    } 
} 

public class test 
{ 
    public static void main(String[] args) 
    { 
    HelloThread hello=new HelloThread(); 
    hello.go(); 
    } 
} 

no estoy seguro de lo que estás tratando de hacer, así que espero que esto no se rompe la funcionalidad de su código.

3

La excepción java.util.ConcurrentModificationException se produce cuando manipula (agrega, elimina) una colección mientras itera sobre la misma colección.

Es probable que desee consumir las entradas de creación en su segundo subproceso mientras que después de haber sido creadas por su primer subproceso. Por lo tanto, podría utilizar ArrayLists get(index) y tamaño () para el control

9

Considere utilizar un CopyOnWriteArrayList que es seguro para la ejecución de subprocesos. Cada vez que agrega un elemento, se crea una copia nueva de la matriz subyacente. Sin embargo, el iterador no reflejará adiciones a la lista desde que se creó el iterador, pero se garantiza que no arrojará ConcurrentModificationException.

arrayList=new CopyOnWriteArrayList(); 
+1

+1 por no reinventar la rueda. – BlairHippo

+1

Cabe señalar que el proceso de copia copia las referencias de elementos para todos los elementos de la lista. Esto escasea pobremente para listas largas. –

10

Otras respuestas han identificado el problema:

  • Los iteradores para colecciones sincronizadas no están sincronizados. De hecho, son simplemente los iteradores devueltos por los objetos de colección dentro de las clases contenedoras.

  • Muchas clases de recopilación (incluido ArrayList) utilizan un mecanismo de recuperación para detectar modificaciones concurrentes durante la iteración. Este comportamiento está claramente documentado en los javadocs para las clases respectivas. Esto es lo que estás viendo.

No todas las clases de colecciones hacen esto.Por ejemplo, muchas de las clases de recopilación java.util.Concurrent... permiten la modificación concurrente durante la iteración, pero relajan la semántica de la secuencia de iteración para que los resultados de las modificaciones puedan o no ser aparentes en los objetos devueltos por el iterador.

El javadoc para Collections.synchronizedList() explica cómo sincronizar el iterador. Básicamente lo que hace esto:

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

(Aparte: normalmente no es seguro asumir que hacer algo como esto funcionaría En teoría, la lista sincronizada podría utilizar un objeto de bloqueo privada, y la declaración synchronized no cerraba. Sin embargo, los javadocs dicen que esto es lo que hay que hacer en este caso ... por lo que es seguro.

El problema al hacerlo es que al bloquear la colección se crea un posible cuello de botella de concurrencia. La alternativa es usar una estructura de datos de copia sobre escritura que internamente haga una copia de las partes relevantes de la colección. Este enfoque significa que un iterador ve una instantánea de la colección. Se pueden hacer modificaciones a la colección simultáneamente con una iteración, pero el iterador no las ve. El problema con el copy-on-write es que las modificaciones son potencialmente mucho más costosas.

En última instancia, debe equilibrar las características y los costos de los diferentes tipos de recopilación con modificaciones simultáneas en comparación con sus necesidades reales. ¿Puede salirse con la suya sin ver todas las modificaciones concurrentes?

+0

Muchas gracias. Salvaste mi día :) – Niklas

0

Tomemos una lista normal (implementada por la clase ArrayList) y sincronícela. Esto se muestra en la clase SynchronizedArrayList. Pasamos el método Collections.synchronizedList una nueva ArrayList of Strings. El método devuelve una lista de cadenas sincronizada. // Aquí está SynchronizedArrayList clase paquete 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 kumar[email protected] * * / SynchronizedArrayList public class { registro Logger estática = Logger.getLogger (SynchronizedArrayList.class.getName()); public void main (String [] args) {estáticas

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()); 
} 
} 

} 
} 

Notice that when iterating over the list, this access is still done using a synchronized block that locks on the synchronizedList object. 
In general, iterating over a synchronized collection should be done in a synchronized block