2012-08-06 24 views
8

El siguiente código causará los mismos problemas, si la variable 'commonSet' de este método fuera un campo de nivel de clase. Si se tratara de un campo de nivel de clase, tendré que ajustar agregar a la operación de configuración dentro de un bloque sincronizado ya que HashSet no es seguro para subprocesos. ¿Debo hacer lo mismo en el siguiente código, ya que varios hilos se están agregando al conjunto o incluso el hilo actual puede continuar mutando el conjunto.Thread Safe: ¿variable de método local final transferida a los hilos?

public void threadCreatorFunction(final String[] args) { 
    final Set<String> commonSet = new HashSet<String>(); 

    final Runnable runnable = new Runnable() { 
     @Override 
     public void run() { 
      while (true) { 
       commonSet.add(newValue()); 
      } 
     } 
    }; 

    new Thread(runnable, "T_A").start(); 
    new Thread(runnable, "T_B").start(); 
} 

La referencia a 'commonSet' está 'bloqueada' mediante el uso de final. Pero múltiples hilos que operan en él aún pueden corromper los valores en el conjunto (¿puede contener duplicados?). En segundo lugar, la confusión es porque 'commonSet' es una variable de nivel de método - es la misma referencia en la memoria de pila del método de llamada (función threadCreator) y la memoria de pila de los métodos de ejecución - ¿es correcto?

Hay un buen número de preguntas relacionadas con esta:

Pero, no puedo verlos haciendo hincapié en la rosca caja parte de ese intercambio/paso del mutables.

+0

Véase también http://stackoverflow.com/questions/1299837/cannot-refer-to-a-non-final-variable-inside-an-inner-class-defined-in-a-differen – nos

Respuesta

9

No, esto no es seguro para subprocesos. El hecho de que lo tenga en una variable final significa que ambos hilos verán la misma referencia , lo que está bien, pero no hace que el objeto sea más seguro para subprocesos.

O necesita sincronizar el acceso, o use ConcurrentSkipListSet.

5

Un ejemplo interesante.

La referencia commonSet es segura e inmutable. Está en la pila para el primer hilo y un campo de tu clase anónima Runnable también. (Puede ver esto en un depurador)

El conjunto commonSet se refiere a es mutable y no es seguro para subprocesos. Debe usar sincronizado o un bloqueo para que sea seguro. (O use una recogida segura de rosca en su lugar)

1

Creo que se está perdiendo una palabra en su primera frase:

Será el siguiente código causa mismos problemas si la variable 'commonSet' de este método era un ??? en su lugar, un campo de nivel de clase.

Creo que estás un poco confundido. Los problemas de concurrencia no tienen nada que ver con si la referencia a su estructura de datos mutable se declara o no final. Debe declarar la referencia como final porque está closing over dentro de la declaración de clase interna anónima para su Runnable. Si realmente va a tener múltiples hilos para leer/escribir la estructura de datos, entonces necesita usar bloqueos (sincronizar) o usar una estructura de datos concurrente como java.util.concurrent.ConcurrentHashMap.

+0

primera línea corregida – haps10

+0

¡Ah, estaba equivocado, tenías una palabra extra! – DaoWen

0

Como otros ya han comentado, está confundiendo algunos conceptos, como definitivo y sincronizado.

Creo que si explica lo que quiere lograr con su código, sería mucho más fácil ayudarle. Tengo la impresión de que este fragmento de código es más un ejemplo que el código real.

Algunas preguntas: ¿Por qué se define el conjunto dentro de la función? ¿debería compartirse entre hilos? Algo que me intriga es que cajón de dos hilos con la misma instancia del ejecutable

new Thread(runnable, "T_A").start(); 
    new Thread(runnable, "T_B").start(); 
0

Si commonset es utilizado por un solo hilo o múltiple Es sólo la referencia que es inmutable para los objetos finales (es decir, una vez que se asigna no puede asignar otra referencia obj nuevamente) sin embargo, puede modificar los contenidos a los que hace referencia este objeto utilizando esa referencia.

Si no fuera final de un hilo podría haber inicializado de nuevo y cambiado la referencia commonSet = new HashSet<String>(); commonSet.add(newValue()); en cuyo caso estos dos hilos pueden utilizar dos commonsets diferentes, que probablemente no es lo que quiere

1

El commonSet se comparte entre dos hilos. Usted lo declaró como definitivo y, por lo tanto, hizo que la referencia fuera inmutable (no puede reasignarla), pero los datos reales dentro del Conjunto aún se pueden modificar. Supongamos que un hilo coloca algunos datos y otro hilo lee algunos datos. Cada vez que el primer hilo coloca datos, lo más probable es que desee bloquear ese conjunto para que ningún otro subproceso pueda leer hasta que se escriban los datos. ¿Eso sucede con un HashSet? Realmente no.