2008-10-02 8 views
9

Al diseñar una clase de colección, ¿hay alguna razón para no implementar el bloqueo de forma privada para que sea seguro? ¿O debería dejar esa responsabilidad al consumidor de la colección?¿Tus colecciones son seguras para hilos?

+1

Si haces que tu colección sea inmutable, será inherentemente segura para los hilos sin que nadie tenga que bloquearla en absoluto. – Juliet

Respuesta

13

¿Hay alguna razón para no implementar el bloqueo de forma privada para que sea seguro?

Depende. ¿Tu objetivo es escribir una clase de colección a la que accedan varios hilos? Si es así, hágalo seguro. Si no, no pierdas tu tiempo. Este tipo de cosas es a lo que la gente se refiere cuando hablan de 'optimización prematura'

Resuelve los problemas que tienes. No trates de resolver problemas futuros que creas que puedes tener en el futuro, porque no puedes ver el futuro e invariablemente estarás equivocado.

Nota: Aún necesita escribir su código de forma mantenible, por ejemplo, si hizo que fuera necesario y agregara el bloqueo a la colección, no sería terriblemente difícil. Mi punto es "no implemente las características que no necesita y no va a usar"

+2

No estoy seguro de comprarlo, no sería terriblemente difícil "parte si le preocupa el rendimiento de subprocesos múltiples. Es fácil de hacer ingenuamente, pero es difícil hacerlo bien. Ve a ver el código de ConcurrentHashMap frente a HashMap. –

+1

Me refería simplemente a agregar un bloqueo ingenuo. Obviamente, si quisieras algo así como un ConcurrentHashMap, entonces tendrías que hacer un trabajo serio –

2

Yo personalmente dejaría en manos de los consumidores. Hará que su clase de colección sea más genérica.

10

Para Java, debe dejar la velocidad sin sincronizar. El consumidor de la colección puede envolver en un synchronization wrapper si lo desea.

2

Solo tenga en cuenta en su documentación que no está haciendo que sea seguro para subprocesos y no lo guarde, o si, para su aplicación, desea que sea seguro para subprocesos, hágalo seguro y anótelo en su documentación para ello. La única regla es documentarlo. Aparte de eso, haga su clase por usted y si otras personas quieren usarlo, pueden hacerlo.

0

Esto haría que sea imposible acceder simultáneamente a una colección de varios hilos, incluso si usted sabe que el elemento que toca no es utilizado por nadie más.

Un ejemplo sería una colección con un acceso directo de índices basado en enteros. Cada hilo puede saber desde su identificación a qué valores de índice puede acceder sin preocuparse por lecturas o escrituras sucias.

Otro caso en el que obtendría un golpe de rendimiento innecesario sería cuando los datos solo se leen de la colección y no se escriben en.

2

Si estoy buscando una clase de colección y necesito capacidades de seguridad de subprocesos y su clase no los tiene, inmediatamente voy a saltar a la próxima oferta para ver lo que ofrecen. Tu colección no captará más mi atención.

Tenga en cuenta el "Si" al principio. Algunos clientes lo querrán, otros no, y a otros no les importará. Si vas a construir un juego de herramientas para los consumidores, ¿por qué no ofrecer ambas variedades? De esa manera, puedo elegir cuál usar, pero si quiero un hilo seguro, todavía tengo mi atención y no tengo que escribirlo yo mismo.

3

Las clases de recopilación deben ser lo más rápidas posible. Por lo tanto, deje los bloqueos fuera.

El código de llamada sabrá dónde están mejor los bloqueos que la clase de colección no. En el peor de los casos, la aplicación tendrá que agregar un bloqueo adicional, lo que significa que se producen dos bloqueos, lo que duplica el golpe de rendimiento.

1

La razón principal para no hacer que el hilo sea seguro es el rendimiento. El código de seguridad del hilo puede ser 100 veces más lento que el código no seguro, por lo que si el cliente no quiere la característica, es un desperdicio bastante grande.

0

Acepto que dejarlo en manos del consumidor es el enfoque correcto. Si proporciona al consumidor mucha más flexibilidad en cuanto a si la instancia de Colección está sincronizada o si un objeto diferente está sincronizado. Por ejemplo, si tenía dos listas que necesitaban actualizarse ambas, podría tener sentido tenerlas en un único bloque sincronizado utilizando un solo bloqueo.

0

Si hace una clase de colección, no la haga segura. Es bastante difícil hacer lo correcto (por ejemplo, correcto y rápido), y los problemas para su consumidor cuando lo hace incorrectamente (heisenbugs) son difíciles de depurar.

En lugar de eso, implemente una de las API de recopilación y use Collections.synchronizedCollection (yourCollectionInstance) para obtener una implementación segura para subprocesos si la necesitan.

Simplemente consulte las Colecciones apropiadas.método synchronizedXXX en tu clase javadoc; dejará en claro que ha considerado la seguridad de subprocesos en su diseño y se aseguró de que el consumidor tenga a su disposición una opción segura para subprocesos.

1

Tenga en cuenta que si intenta hacer que cualquier clase sea segura para subprocesos, debe decidir sobre los escenarios de uso común.

Por ejemplo, en el caso de una colección, hacer todas las propiedades y métodos individualmente con seguridad de subprocesos podría no ser lo suficientemente bueno para un consumidor, ya que leer primero el recuento y luego repetir, o similar, no funcionaría mucho bien si el conteo cambia después de leerlo.

1

Hacer que la recolección sea segura para el hilo es lo que mató a las clases Vector y Hashtable de Java. Es mucho más fácil para un cliente envolverlo en un contenedor seguro para hilos, como se sugirió anteriormente, o sincronizar el acceso a datos en el subconjunto de métodos, que tomar un golpe de sincronización cada vez que se accede a la clase. Casi nadie usa Vector o Hashtable, y si lo hacen, se ríen de ellos, porque sus reemplazos (ArrayList y HashMap) son mucho más rápidos. Lo cual es desafortunado, ya que yo (proveniente de un fondo de C++) prefiero mucho el nombre "Vector" (STL), pero ArrayList llegó para quedarse.

1

Básicamente, diseñe su colección como hilo seguro, con bloqueo implementado en dos métodos de su clase: bloqueo() y desbloqueo(). Llámalos a cualquier lugar que necesites, pero déjalos vacíos. Luego, subclase su colección implementando los métodos lock() y unlock(). Dos clases por el precio de uno.

1

Una buena razón para NO hacer que su colección sea segura para subprocesos es para mejorar el rendimiento de un solo subproceso. Ejemplo: ArrayList sobre Vector. Aplazar la seguridad de la hebra a la persona que llama permite que la caja de uso no sincronizada se optimice evitando el bloqueo.

Una buena razón para hacer que su colección sea segura para subprocesos es para mejorar el rendimiento de subprocesos múltiples. Ejemplo: ConcurrentHashMap sobre HashMap. Debido a que CHM internaliza las preocupaciones de múltiples subprocesos, puede bloquear por bandas para un mayor acceso concurrente de manera más efectiva que la sincronización externa.

0

He aquí un buen comienzo.

thread-safe-dictionary

Pero se dará cuenta de que se pierda uno de las grandes características de colecciones - enumeración. No se puede subprocesar un enumerador, simplemente no es realmente factible, a menos que implemente su propio enumerador que retiene un bloqueo de instancia en la colección misma. Sospecho que esto causaría cuellos de botella y bloqueos potenciales.

6

Las colecciones de Thread safe pueden engañar. Jared Par publicó un par de artículos interesantes sobre las colecciones de seguridad de rosca:

El problema es que hay varios niveles de colecciones de seguridad de rosca. Me parece que cuando la mayoría de la gente dice hilo recolección segura de lo que realmente quieren decir “una colección que no sea corrompido cuando se modifican y se accede desde varios subprocesos”

...

Pero si la construcción de una La lista de seguridad de subprocesos de datos es tan fácil, ¿por qué Microsoft no agrega estas colecciones estándar en el marco ?

Respuesta: ThreadSafeList es una clase prácticamente inutilizable porque el diseño le lleva por el camino de mal código .

Los defectos en este diseño no son aparentes hasta que examine cómo se usan comúnmente las listas . Por ejemplo, tome el siguiente código que intenta tomar el primer elemento fuera de la lista si hay uno.

static int GetFirstOrDefault(ThreadSafeList<int> list) { 
    if (list.Count > 0) { 
     return list[0]; 
    } 
    return 0; } 

Este código es una condición de carrera clásica. Considere el caso donde solo hay un elemento> en la lista. Si otro hilo elimina ese elemento entre el enunciado if y el enunciado return, el enunciado return emitirá una excepción porque está tratando de acceder a un índice no válido en la lista. A pesar de que ThreadSafeList es seguro para hilos de datos, no hay nada que garantice la validez de un valor de retorno de una llamada a través de la siguiente llamada al mismo objeto

http://blogs.msdn.com/b/jaredpar/archive/2009/02/11/why-are-thread-safe-collections-so-hard.aspx

http://blogs.msdn.com/b/jaredpar/archive/2009/02/16/a-more-usable-thread-safe-collection.aspx

0

A partir de JDK 5 si necesitas una colección segura para subprocesos que vería primero si una de las colecciones ya implementadas en java.util.concurrent funcionara. Como señalan los autores de Java Concurrency In Practice (incluido el tipo que escribió la mayoría de las clases) implementarlas correctamente es muy difícil, especialmente si el rendimiento es importante.

Citando http://download.oracle.com/javase/6/docs/api/java/util/concurrent/package-summary.html

concurrentes Colecciones

Además de colas, esta suministros paquete implementaciones colección diseñada para su uso en contextos multiproceso: ConcurrentHashMap, ConcurrentSkipListMap, ConcurrentSkipListSet, CopyOnWriteArrayList, y CopyOnWriteArraySet.Cuando se espera que muchos hilos para acceder a un colección dada, un ConcurrentHashMap es normalmente preferible a un sincronizado HashMap, y una ConcurrentSkipListMap es normalmente preferible a una TreeMap sincronizado . A CopyOnWriteArrayList es preferible a una ArrayList sincronizada cuando el número esperado de lecturas y recorre mucho más que el número de actualizaciones de una lista.

Cuestiones relacionadas