6

El libro bien aclamado JCIP dice esto sobre el uso ThreadLocal:¿De qué manera el uso ThreadLocal reducir reutilización

Es fácil abusar ThreadLocal mediante el tratamiento de su propiedad confinamiento de hilo como una licencia para utilizar variables globales o como un medio de creando argumentos de métodos "ocultos". Las variables de subprocesos locales pueden restar reutilización e introducir acoplamientos ocultos entre las clases, por lo que deben utilizarse con cuidado.

¿Qué significa decir que las variables Thread-local pueden reducir la reutilización e introducir acoplamientos ocultos entre las clases?

+0

He hecho una edición de mi respuesta con un simple ejemplo de código. – Tudor

Respuesta

10

Reducen la reutilización casi de la misma manera que las variables globales: cuando los cálculos de su método dependen del estado que es externo al método, pero no se pasan como parámetros (campos de clase por ejemplo), su método es menos reutilizable, porque está estrechamente relacionado con el estado del objeto/clase en el que reside (o peor, en una clase diferente por completo).

Editar: Ok, aquí hay un ejemplo para hacerlo más claro. He usado ThreadLocal solo por el bien de la pregunta, pero se aplica a las variables globales en general. Supongamos que quiero calcular la suma de los primeros N enteros en paralelo en varios hilos. Sabemos que la mejor manera de hacerlo es calcular las sumas locales para cada hilo y resumirlas al final. Por alguna razón decidimos que el método de cada Taskcall utilizará una variable ThreadLocal sum que se define en una clase diferente como una variable global (estática):

class Foo { 
    public static ThreadLocal<Long> localSum = new ThreadLocal<Long>() { 
     public Long initialValue() { 
      return new Long(0);   
     } 
    }; 
} 

class Task implements Callable<Long> { 

    private int start = 0; 
    private int end = 0;  

    public Task(int start, int end) { 
     this.start = start; 
     this.end = end; 
    } 

    public Long call() { 
     for(int i = start; i < end; i++) { 
      Foo.localSum.set(Foo.localSum.get() + i); 
     } 
     return Foo.localSum.get(); 
    } 
} 

El código funciona correctamente y nos da el valor esperado de la suma global, pero notamos que la clase Task y su método call ahora están estrictamente acoplados a la clase Foo. Si quiero reutilizar la clase Task en otro proyecto, también debo mover la clase Foo, de lo contrario, el código no se compilará.

Aunque este es un ejemplo simple complicado a propósito, puede ver los peligros de las variables globales "ocultas". También afecta la legibilidad, ya que alguien más que lea el código también deberá buscar la clase Foo y ver cuál es la definición de Foo.localSum. Debes mantener tus clases tan autónomas como sea posible.

+0

@Subhra - ¿No es la respuesta de Tudor lo suficientemente clara? ¿Por qué necesita específicamente 'código de ejemplo'? –

+0

@Subhra: He hecho una edición con un ejemplo de código simple. – Tudor

3

Se ha declarado ThreadLocal por subproceso: normalmente se declara un campo por objeto de esa clase. A partir de esto, puede haber un montón de cosas que pueden salir mal si se usa incorrectamente el ThreadLocal.

Si un hilo pasa a través de varios objetos, (ya sea de una o de varias clases), el ThreadLocal utilizado por este hilo es la misma instancia en todas estas instancias. Este es el acoplamiento del que BG está hablando. En el momento en que hay un acoplamiento, la reutilización se vuelve difícil y propensa a errores.

+0

El documento de Java sobre ThreadLocal dice que, por lo general, ThreadLocal debe ser privado estático, pero que ThreadLocal no lo aplica. Así que, técnicamente, ThreadLocal puede ser por hilo por instancia. Sin embargo, su segundo párrafo responde bastante bien la pregunta. – Inquisitive