2012-04-11 8 views
6

Cuál de las opciones de ThreadLocal o una variable local en Runnable se preferirá. Por razones de rendimiento. Espero que el uso de una variable local dará más posibilidades para el almacenamiento en caché de la CPU, etc.ThreadLocal vs variable local en Runnable

Gracias por cualquier ayuda.

+0

Si está interesado únicamente en el rendimiento de ThreadLocal frente a las variables locales, esta pregunta tiene mucha lectura: http://stackoverflow.com/questions/609826/performance-of-threadlocal-variable – Alex

Respuesta

14

Cuál de entre ThreadLocal o una variable local en Runnable será preferido.

Si tiene una variable que se declara dentro de la clase del hilo (o la Runnable), entonces una variable local funcionará y no necesita el ThreadLocal.

new Thread(new Runnable() { 
    // no need to make this a thread local because each thread already 
    // has their own copy of it 
    private SimpleDateFormat format = new SimpleDateFormat(...); 
    public void run() { 
     ... 
     // this is allocated per thread so no thread-local 
     format.parse(...); 
     ... 
    } 
}).start(); 

ThreadLocal se utilizan para guardar el estado en función de cada hilo cuando se está ejecutando código común. Por ejemplo, el SimpleDateFormat (desafortunadamente) no es seguro para subprocesos, por lo tanto, si desea usarlo, deberá almacenar uno en un ThreadLocal para que cada subproceso tenga su propia versión del formato.

private final ThreadLocal<SimpleDateFormat> localFormat = 
    new ThreadLocal<SimpleDateFormat>() { 
     @Override 
     protected SimpleDateFormat initialValue() { 
      return new SimpleDateFormat(...); 
     } 
    }; 
... 
// if a number of threads run this common code 
SimpleDateFormat format = localFormat.get(); 
// now we are using the per-thread format (but we should be using Joda Time :-) 
format.parse(...); 

Un ejemplo de cuando esto es necesario es un controlador de solicitud web. Los subprocesos se asignan en Jetty land (por ejemplo) en algún tipo de grupo que está fuera de nuestro control. Una solicitud web entra en su ruta para que Jetty llame a su controlador. Necesita tener un objeto SimpleDateFormat, pero debido a sus limitaciones, debe crear uno por hilo. Ahí es cuando necesita un ThreadLocal. Cuando está escribiendo un código de reentrada al que varios subprocesos pueden llamar y desea almacenar algo por subproceso.

Si desea pasar argumentos a su Runnable, debe crear su propia clase y luego puede acceder al constructor y pasar los argumentos.

new Thread(new MyRunnable("some important string")).start(); 
... 
private static class MyRunnable implements { 
    private final String someImportantString; 
    public MyRunnable(String someImportantString) { 
     this.someImportantString = someImportantString; 
    } 
    // run by the thread 
    public void run() { 
     // use the someImportantString string here 
     ... 
    } 
} 
+0

Agradable, pero Cambiaría el ejemplo de ThreadLocal para inicializar localFormat con una subclase anónima que anula initialValue, ya que ese es el patrón de uso típico. – Alex

+0

me malinterpretas.Mire el código de ejemplo en el Javadoc para ThreadLocal: muestra cómo colocar correctamente el código de inicialización para la variable por subproceso en un lugar común para que se inicialice para cada subproceso de llamada antes de ser devuelto por get(), sin importar dónde esté llamado desde. – Alex

+0

Huh, derecha @Alex. No estoy seguro de haberlo usado alguna vez. ¡Bonito! Gracias. – Gray

3

Cada vez que su programa podría utilizar correctamente cualquiera de los (variable local o ThreadLocal) dos, elegir la variable local: será con más prestaciones.

ThreadLocal es para almacenar el estado por subproceso más allá del alcance de ejecución de un método. Obviamente, las variables locales no pueden persistir más allá del alcance de su declaración. Si los necesita, ahí es cuando puede comenzar a usar un ThreadLocal.

Otra opción es usar synchronized para administrar el acceso a una variable de miembro compartida. Este es un tema complicado y no me molestaré en examinarlo aquí, ya que ha sido explicado y documentado por personas más articuladas que yo en otros lugares. Obviamente, esto no es una variante del almacenamiento "local": compartiría el acceso a un solo recurso de una manera segura para la ejecución de subprocesos.

+0

Nunca he entendido el almacenamiento de ThreadLocal. He estado escribiendo aplicaciones multiproceso durante 30 años y nunca he usado TLS. Cuando se inicia un hilo, la llamada CreateThread(), o lo que sea, toma la dirección cuando se debe ejecutar el hilo. En la mayoría de los lenguajes, este es un procedimiento/función y una variable de pila local declarada tendrá la vida útil del hilo. En los lenguajes OO, usualmente hay un parámetro extra en la llamada de creación que puede transferir 'esto' y, por lo tanto, un hilo también puede tener miembros de datos de instancia. Entonces, ¿por qué TLS? ¿Qué me da eso es "especial"? –

1

Responde a esta pregunta mediante la simple regla de que una variable debe declararse en el ámbito delimitador más pequeño posible. Un ThreadLocal es el alcance envolvente más grande posible, por lo que solo debe usarlo para los datos que se necesitan en muchos ámbitos léxicos. Si puede ser una variable local, debería serlo.

+0

Creo que deberían llamarse 'Thread Globals', entonces nadie los usaría. Durante años, leí publicaciones, blogs, artículos 'No usar variables globales'. Entonces, alguien decide que los hilos pueden tener algo llamado 'TLS' - yippee! Globales de nuevo, pero con otro nombre para que se mantengan frescos. ¿Está bien ahora escribir programas de subprocesos únicos con muchas variables globales, siempre y cuando estén almacenados en el TLS del hilo principal? En mi humilde opinión, esta cosa TLS es una característica tonta que no resuelve nada nuevo. –

+0

@MartinJames Estoy totalmente de acuerdo. Los he usado aproximadamente dos veces en 15 años y lo lamenté todo el tiempo. – EJP

+0

@MartinJames Estoy de acuerdo en que 'ThreadLocal's se debe usar con moderación o, preferiblemente, de ninguna manera. –

1

También me confundí por qué necesito ThreadLocal cuando puedo usar variables locales, ya que ambas mantienen su estado dentro de un hilo. Pero después de mucha búsqueda y experimentación, veo por qué es necesario ThreadLocal.

encontré dos usos hasta ahora -

valores específicos hilo
  1. de verano en el interior del mismo objeto compartido
  2. Alternativa a pasar variables como parámetros a través de N-capas de código

1:

Si tiene dos hilos que operan en el mismo objeto y ambos hilos modifican este objeto - entonces ambos hilos siguen perdiendo sus modificaciones el uno al otro.

Para hacer que este objeto tenga dos estados separados para cada hilo, declaramos este objeto o parte de él ThreadLocal.

Por supuesto, ThreadLocal solo es beneficioso aquí porque ambos hilos comparten el mismo objeto. Si están utilizando diferentes objetos, no es necesario que los objetos sean ThreadLocal.

2:

El segundo beneficio de ThreadLocal, parece ser un efecto secundario de la forma de su ejecución.

Una variable ThreadLocal puede ser .set() por un hilo, y luego ser .get() en cualquier parte else. .get() recuperará el mismo valor que este subproceso había establecido en cualquier otro lugar. Necesitaremos un contenedor global disponible para hacer un .get() y .set(), para realmente escribir el código.

Cuando hacemos un threadLocalVar.set() - es como si estuviera dentro de un "mapa" global, donde este es la clave.

Como si - someGlobalMap.put (Thread.currentThread(), threadLocalVar);

Así que diez capas hacia abajo, cuando hacemos threadLocalVar.get() - obtenemos el valor que este hilo había establecido diez capas.

threadLocalVar = someGlobalMap.get (Thread.currentThread());

Por lo tanto, la función en décimo nivel no tiene que arrastrarse alrededor de esta variable como parámetro, y puede acceder a ella con .get() sin preocuparse por si es del hilo correcto.

Por último, dado que una variable ThreadLocal es una copia para cada hilo, por supuesto, no necesita sincronización. He entendido mal a ThreadLocal anteriormente como una alternativa a la sincronización, que no lo es. Es solo un efecto secundario de eso, que no necesitamos sincronizar la actividad de esta variable ahora.

Espero que esto haya ayudado.

Cuestiones relacionadas