2011-05-26 14 views
9

Tengo una pregunta. ¿Qué sucede cuando trato de agregar el "mismo" objeto dos veces a una ArrayList? Con "lo mismo" me refiero a un objeto de una clase individual, que se identifica como lo mismo con equals() y hashCode(). Tiene diferentes valores para la mayoría de las variables miembro y se creó a partir de hilos quizás diferentes, pero para equals() y hashCode() es el "mismo". ¿El segundo objeto reemplaza el primer objeto?ArrayList - agregue los "mismos" objetos (same => equals, hashCode), Threads

Además, ¿qué sucede si dos subprocesos intentan agregar esos objetos exactamente al mismo tiempo al ArrayList? ¿Esto es posible? Si es así, ¿qué sucede?

¡Gracias! :-)

[EDITAR] ¡Gracias por todas las respuestas! ¿Debería usar synchronizedList en lugar de utilizar "sincronizar (enumerar) {}"? -> Leí los documentos, incluso con synchronizedList, para iterar sincronizar (list) se usará

[EDIT2] ¿Se puede declarar una synchronizedList como una variable miembro? Lo intenté, pero no funcionó.

Respuesta

12

No, ArrayList no intenta detectar duplicados en absoluto; puede tener un ArrayList apareciendo la misma referencia varias veces. Si desea una colección para evitar duplicados, necesita una implementación de Set, y si también desea conservar el orden de inserción, probablemente desee LinkedHashSet.

Tenga en cuenta, sin embargo, que sin bloquear ArrayList debe no mutar desde varios subprocesos en el primer lugar - es simplemente no pretende ser una colección de hilos de proceso seguro de esa manera. Varios hilos pueden leer desde un ArrayList sin sincronización, pero no mutarlo. De los documentos:

Tenga en cuenta que esta implementación no está sincronizada. Si varios subprocesos acceden a una instancia de ArrayList al mismo tiempo, y al menos uno de los subprocesos modifica estructuralmente la lista, debe estar sincronizada externamente. (Una modificación estructural es cualquier operación que agrega o elimina uno o más elementos, o cambia el tamaño explícitamente de la matriz de respaldo, simplemente establecer el valor de un elemento no es una modificación estructural). Esto normalmente se logra sincronizando en algún objeto que naturalmente encapsula el lista. Si no existe tal objeto, la lista debe ser "ajustada" utilizando el método Collections.synchronizedList. Esto se hace mejor en tiempo de creación, para evitar el acceso no sincronizado accidental a la lista

Si desea mutar una colección de múltiples hilos sin bloquear, sugiero nos fijamos en las colecciones en java.util.concurrent.

4

Permitirá agregar simplemente. La lista no tiene nada que ver con hashCode(), equals() durante la inserción, no tiene en cuenta el duplicado.

ArrayList no es seguro para subprocesos, por lo que es posible que no obtenga el resultado deseado. puede tener synchronizedList de Collections clase

2

Un ArrayList puede contener varias referencias al mismo objeto exacto (equivalencia de identidad). No marca equals() o hashCode() al agregar objetos.

Acabará con dos referencias en su ArrayList.

ArrayList NO es seguro para subprocesos ... por lo que no está definido el comportamiento si intenta agregar dos subprocesos al mismo tiempo. Tal vez intente usar un SynchronizedList si quiere hacer algo como eso.

6

¿El segundo objeto entonces reemplaza el primer objeto?

No, la mayoría de los desarrolladores hacer controles explícitos

if(!list.contains(foo)){ 
    list.add(foo); 
} 

Además, ¿qué ocurre si dos subprocesos intentan añadir esos objetos exactamente en el mismo tiempo a ArrayList? ¿Es esto posible? Si es así, ¿qué sucede?

Sí, esto es posible. Si varios subprocesos escriben/leyendo de la misma ArrayList, a continuación, utilizar la palabra clave synchronized cada vez que acceda a esta lista

public List<Foo> getFoos(){ 
    synchronized(list){ 
     return list; 
    } 
} 

public void addFoo(Foo foo){ 
    synchronized(list){ 
     list.add(foo); 
    } 
} 

EDITAR

Como alguien señaló, supongo comprobar si el ArrayList contiene el objeto que se agregará es bastante caro. Si quiere asegurarse de que el objeto solo se agregue una vez, seguiría la recomendación que se hace a continuación de usar un LinkedHashSet. De acuerdo con el API, cuando se trata de add a esta estructura de datos que

añade el elemento especificado a este conjunto si no está ya presente. Más formalmente, agrega el elemento especificado e a este conjunto si este conjunto no contiene elemento e2 tal que (e == nulo? e2 == nulo: e.equals (e2)). Si este conjunto ya contiene el elemento, la llamada deja sin cambios el conjunto y devuelve falsa.

+0

-1 Cada llamada a 'ArrayList.contains' es O (n). Esta es una manera terrible de crear una lista única. 'LinkedHashSet' es mejor para eso. –

+0

pero al usar LinkedHashSet al acceder, debe estar sincronizado también, ¿correcto? Entonces, ¿por qué no utilizar una synchronizedList? – nano7

+0

@ nano7, por supuesto, debe estar sincronizado. solo porque haya cambiado la colección no significa que cambie la política de sincronización. puede utilizar cualquier estructura de datos sincronizada que desee, pero si va a utilizar un 'LinkedHashSet', le recomendaría usar' synchronizedSet'. – mre

1

Si intenta agregar el mismo objeto dos veces, funcionará, o si intenta agregar 2 objetos con todo igual, seguirá funcionando. No es una buena práctica hacerlo porque es más difícil mantener la lista.

general: usted no debe hacerlo

Cuestiones relacionadas