2009-11-21 23 views
16

Entiendo que las colecciones como Hashtable están sincronizadas, pero ¿alguien me puede explicar cómo funciona, y en qué punto (s) el acceso está restringido a llamadas simultáneas? Por ejemplo, digamos que yo uso algunos iteradores como este:¿Explicar la sincronización de colecciones cuando se usan iteradores?

Hashtable<Integer,Integer> map = new Hashtable<Integer,Integer>(); 

void dosomething1(){ 
    for (Iterator<Map.Entry<Integer,Integer>> i = map.entrySet().iterator(); i.hasNext();){ 
     // do something 
    } 
} 
void dosomething2(){ 
    for (Iterator<Map.Entry<Integer,Integer>> i = map.entrySet().iterator(); i.hasNext();){ 
     // do something 
     // and remove it 
     i.remove(); 
    } 
} 
void putsomething(int a, int b){ 
    map.put(a,b); 
} 
void removesomething(int a){ 
    map.remove(a); 
} 
var clear(){ 
    map = new Hashtable<Integer,Integer>(); 
} 

Por favor alguien puede explicar si hay dificultades con que me llama estas funciones al azar en diferentes hilos? ¿Cómo hace el iterador, en particular, su sincronización, especialmente cuando está utilizando entrySet(), que también parece requerir sincronización? ¿Qué ocurre si se invoca clear() mientras uno de los bucles está en curso? ¿Qué ocurre si removevesomething() elimina un elemento que todavía no se procesa mediante un bucle simultáneo en dosomething1()?

¡Gracias por cualquier ayuda!

Respuesta

34

iteración sobre las colecciones en Java no es hilo de seguridad, incluso si está utilizando una de las envolturas sincronizados (Collections.synchronizedMap(...)):

Es imperativo que el usuario sincronizar manualmente en el mapa devuelto cuando se itera sobre cualquiera de sus puntos de vista de recogida:

Map m = Collections.synchronizedMap(new HashMap()); 
... 
Set s = m.keySet(); // Needn't be in synchronized block 
... 
synchronized(m) { // Synchronizing on m, not s! 
    Iterator i = s.iterator(); // Must be in synchronized block 
    while (i.hasNext()) 
     foo(i.next()); 
} 

Java Collection Framework docs

Otras llamadas a colecciones sincronizados son seguros, ya que las clases contenedoras les rodean con synchronized bloques, que utilizan la colección de envoltura como su monitor de:

public int size() { 
    synchronized(this) { 
     return collection.size(); 
    } 
} 

con collection siendo la colección original. Esto funciona para todos los métodos expuestos por una colección/mapa, a excepción de las cosas de iteración.

El conjunto de teclas de un mapa se sincroniza de la misma manera: el contenedor sincronizado no devuelve en absoluto el conjunto de claves original. En cambio, devuelve un contenedor sincronizado especial del conjunto de claves original de la colección. Lo mismo se aplica al conjunto de entrada y al conjunto de valores.

+0

Se corrigió la respuesta: el monitor utilizado es realmente la colección contenedora, no la original. – Dirk

+0

Eso es súper útil y se presenta muy bien. Estaba teniendo problemas para encontrar una fuente que explique esto claramente, ¡muchas gracias! – DivideByHero

+0

"La iteración sobre colecciones en Java no es segura para subprocesos, incluso si está utilizando una de las envolturas sincronizadas" O_o terrible – rkarajan

Cuestiones relacionadas