2012-02-23 10 views
7

Si tengo una colección sincronizada como estose sincroniza el método toArray() de Collection sincronizado?

Collection c = Collections.synchronizedCollection(myCollection);

Javadoc para las synchronizedCollection mentiones esa iteración externo deben estar sincronizados como esto:

synchronized (c) { 
Iterator i = c.iterator(); 
while (i.hasNext()) { 
    process (i.next()); 
} 
} 

¿Puedo asumir que c.toArray() está sincronizado y por lo tanto no se los cambios en la colección ocurrirán cuando el método se ejecute?

o necesito para sincronizarlo así:

synchronized (c) { 
    c.toArray(); 
} 
+0

¿De dónde viene 'CollectionUtils'? Esa no es una clase de API Java estándar. – Jesper

+0

Supongo que quiere decir 'java.util.Collections', no' CollectionUtils'. – skaffman

+0

Es la clase de utilidad de las Colecciones de Apache Commons –

Respuesta

5

Desde el Javadoc para synchronizedCollection:

devuelve una colección sincronizada (thread-safe) respaldado por la colección especificada.

Por lo tanto, c.toArray() no requiere ninguna sincronización adicional. El método SynchronizedCollection de toArray() hará el bloqueo por usted. En esencia, ese es el objetivo de synchronizedCollection().

Si desea confirmar que esta lectura del contrato concuerda con la implementación real, consulte GrepCode.

+0

Gracias, eso lo dice todo. ¡Y GrepCode es fantástico! – artur

+0

Absolutamente incorrecto. NO PUEDE Y NO DEBE confiar en la implementación del código. DEBE confiar en el contrato suministrado, y como parece que no se ha proporcionado un contrato, NO PUEDE asumir que está sincronizado. – Woot4Moo

+0

@ Woot4Moo Los javadocs 'synchronized *' methods 'son bastante generales, ¿eso significa que nunca deberíamos usarlos? Todo lo que realmente dice es que es seguro para subprocesos, pero creo que es seguro asumir que esto significa que * todos * sus métodos son seguros para subprocesos. La advertencia/ejemplo sobre iteradores también implica que la seguridad del hilo proviene de la sincronización en el objeto devuelto. – yshavit

2

Si está hablando de la utilidad de recolección de commons de Apache, la respuesta es sí. CollectionUtils.synchronizedCollection(...) devuelve una instancia de SynchronizedCollection que está toArray() método es:

public Object[] toArray() { 
     synchronized (lock) { 
      return collection.toArray(); 
     } 
    } 
+0

Gracias. En realidad, me refiero a la clase estándar 'java.util.Collections'. Pero puedo ver que el asnwer es el mismo para ambos. – artur

1

Usted no lo necesita, el método realiza la sincronización para usted.

0

Si está utilizando java.util.Collections que forma parte de la API de recopilación de Java estándar, todos los métodos en la SynchronizedCollection devuelta se sincronizarán incluyendo toArray(). Vea los bloques de código a continuación, tomados del código fuente de Java en java.util.Collections.SynchronizedCollection.

public Object[] toArray() { 
    synchronized(mutex) {return c.toArray();} 
} 

public <T> T[] toArray(T[] a) { 
    synchronized(mutex) {return c.toArray(a);} 
} 
+0

No. Debe confiar en el contrato y no en la implementación. – Woot4Moo

+0

@ Woot4Moo Estoy de acuerdo con usted en que uno no debe confiar en la implementación, solo en el contrato. Los fragmentos de código del código fuente de Java eran para dar una idea más clara de lo que realmente está sucediendo. JavaDoc indica claramente _Returna una colección sincronizada (thread-safe) respaldada por la colección especificada_ que se interpreta como todos los métodos en la colección devuelta están sincronizados. No creo que haya ambigüedad en los documentos sobre eso. – IceMan

+0

si lee el documento completo, indica claramente que la iteración debe estar sincronizada. Si puede convertir estructuras de datos sin iteración, muéstreme. – Woot4Moo

0

Parece que hay una gran idea errónea de que puede confiar en la implementación real del código fuente. Esto es falso, debe confiar en el contrato del método. Dado que el contrato no existe, no puede suponer que hará algo, en cualquier momento la implementación subyacente puede cambiar. Por ejemplo, observe la siguiente función:

/** 
* Returns an empty Collection of Books. 
* 
* 
*/ 
public Collection returnEmptyBooks() 
{ 
    return new HashSet<Book>(); 
} 

Esto implica que puedo devolver cualquier cosa que implemente la interfaz de Colección. Firma más documentación. No se puede suponer que esté sincronizado o cualquier otra cosa de esa naturaleza. También podría deducir que nunca volverá a obtener null de este método, a menos que el contrato haya sido violado.

En caso de que nadie lea los comentarios. Cualquier conversión de una estructura de datos a otra implica iteración. No puede pasar de List a Set sin iterar sobre todos los elementos. Lo mismo se aplicaría con una conversión a una matriz. Debe completar la matriz iterando sobre su estructura de datos inicial, por lo tanto, debe estar sincronizada.

+0

No creo entender su punto. Si por contrato quiere decir estrictamente la firma de un método, entonces en su ejemplo anterior no es cierto que devolver el valor nulo del 'returnEmptyBooks()' infringe el contrato. De hecho, cualquier método que devuelva cualquier java.lang.Object puede devolver un valor nulo y solo puede ser una ** convención ** para devolver la colección vacía y no nulo. Esta convención es específica para la implementación y, según su razonamiento, tampoco debe confiar en ella. – artur

+0

@artur Contract significa firma + documentación. Si observa la documentación proporcionada, indica explícitamente que devolverá una Colección de libros vacía. Mi razonamiento sigue en pie, ya que una pieza de código que invocaría esto estaría garantizada para recibir una Colección vacía y no nula. Si se devuelve null, sería una violación del contrato. Hay muchas más cosas que entran en DbC que solo declaraciones de funciones. – Woot4Moo

+0

Te entiendo. Pero volviendo a mi pregunta original, el javadoc dice explícitamente que devuelve una colección sincronizada (thread-safe). En base a esto, ¿aún no está contento de que pueda suponer que toArray() de Collection reintegrado está sincronizado y es seguro para la ejecución de hilos? – artur

Cuestiones relacionadas