Java Language
ThreadLocal
Buscar..
Observaciones
Se utiliza mejor para objetos que dependen de elementos internos durante la invocación de una llamada, pero de lo contrario no tienen estado, como SimpleDateFormat
, Marshaller
Para el uso Random
ThreadLocal, considere usar ThreadLocalRandom
ThreadLocal Java 8 inicialización funcional
public static class ThreadLocalExample
{
private static final ThreadLocal<SimpleDateFormat> format =
ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyyMMdd_HHmm"));
public String formatDate(Date date)
{
return format.get().format(date);
}
}
Uso básico de ThreadLocal
Java ThreadLocal
se utiliza para crear variables locales de subprocesos. Se sabe que los subprocesos de un Objeto comparten sus variables, por lo que la variable no es segura para subprocesos. Podemos usar la sincronización para la seguridad de los subprocesos, pero si queremos evitar la sincronización, ThreadLocal nos permite crear variables que son locales para el subproceso, es decir, solo ese subproceso puede leer o escribir en esas variables, por lo que los otros subprocesos ejecutan el mismo fragmento de código. no podrá acceder a las variables ThreadLocal de los demás.
Esto puede ser usado, podemos usar variables ThreadLocal
. en situaciones en las que tiene un grupo de subprocesos como, por ejemplo, en un servicio web. Por ejemplo, la creación de un objeto SimpleDateFormat
cada vez que se realiza cada solicitud requiere mucho tiempo y no se puede crear uno estático, ya que SimpleDateFormat
no es seguro para subprocesos, por lo que podemos crear un ThreadLocal para que podamos realizar operaciones seguras para subprocesos sin la sobrecarga de crear SimpleDateFormat
cada hora.
La siguiente pieza de código muestra cómo se puede usar:
Cada hilo tiene su propia variable ThreadLocal
y pueden usar los métodos get()
y set()
para obtener el valor predeterminado o cambiar su valor local a Thread.
ThreadLocal
instancias de ThreadLocal
suelen ser campos estáticos privados en clases que desean asociar el estado con un hilo.
Aquí hay un pequeño ejemplo que muestra el uso de ThreadLocal en el programa java y demuestra que cada hilo tiene su propia copia de la variable ThreadLocal
.
package com.examples.threads;
import java.text.SimpleDateFormat;
import java.util.Random;
public class ThreadLocalExample implements Runnable{
// SimpleDateFormat is not thread-safe, so give one to each thread
// SimpleDateFormat is not thread-safe, so give one to each thread
private static final ThreadLocal<SimpleDateFormat> formatter = new ThreadLocal<SimpleDateFormat>(){
@Override
protected SimpleDateFormat initialValue()
{
return new SimpleDateFormat("yyyyMMdd HHmm");
}
};
public static void main(String[] args) throws InterruptedException {
ThreadLocalExample obj = new ThreadLocalExample();
for(int i=0 ; i<10; i++){
Thread t = new Thread(obj, ""+i);
Thread.sleep(new Random().nextInt(1000));
t.start();
}
}
@Override
public void run() {
System.out.println("Thread Name= "+Thread.currentThread().getName()+" default Formatter = "+formatter.get().toPattern());
try {
Thread.sleep(new Random().nextInt(1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
formatter.set(new SimpleDateFormat());
System.out.println("Thread Name= "+Thread.currentThread().getName()+" formatter = "+formatter.get().toPattern());
}
}
Salida:
Thread Name= 0 default Formatter = yyyyMMdd HHmm
Thread Name= 1 default Formatter = yyyyMMdd HHmm
Thread Name= 0 formatter = M/d/yy h:mm a
Thread Name= 2 default Formatter = yyyyMMdd HHmm
Thread Name= 1 formatter = M/d/yy h:mm a
Thread Name= 3 default Formatter = yyyyMMdd HHmm
Thread Name= 4 default Formatter = yyyyMMdd HHmm
Thread Name= 4 formatter = M/d/yy h:mm a
Thread Name= 5 default Formatter = yyyyMMdd HHmm
Thread Name= 2 formatter = M/d/yy h:mm a
Thread Name= 3 formatter = M/d/yy h:mm a
Thread Name= 6 default Formatter = yyyyMMdd HHmm
Thread Name= 5 formatter = M/d/yy h:mm a
Thread Name= 6 formatter = M/d/yy h:mm a
Thread Name= 7 default Formatter = yyyyMMdd HHmm
Thread Name= 8 default Formatter = yyyyMMdd HHmm
Thread Name= 8 formatter = M/d/yy h:mm a
Thread Name= 7 formatter = M/d/yy h:mm a
Thread Name= 9 default Formatter = yyyyMMdd HHmm
Thread Name= 9 formatter = M/d/yy h:mm a
Como podemos ver en la salida, Thread-0 ha cambiado el valor de formateador pero aún así el formateador predeterminado de thread-2 es el mismo que el valor inicializado.
Múltiples hilos con un objeto compartido.
En este ejemplo, solo tenemos un objeto, pero se comparte entre / ejecuta en diferentes subprocesos. El uso normal de los campos para guardar el estado no sería posible porque el otro hilo también lo vería (o probablemente no lo vería).
public class Test {
public static void main(String[] args) {
Foo foo = new Foo();
new Thread(foo, "Thread 1").start();
new Thread(foo, "Thread 2").start();
}
}
En Foo contamos desde cero. En lugar de guardar el estado en un campo, almacenamos nuestro número actual en el objeto ThreadLocal, al que se puede acceder de forma estática. Tenga en cuenta que la sincronización en este ejemplo no está relacionada con el uso de ThreadLocal, sino que garantiza una mejor salida de la consola.
public class Foo implements Runnable {
private static final int ITERATIONS = 10;
private static final ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>() {
@Override
protected Integer initialValue() {
return 0;
}
};
@Override
public void run() {
for (int i = 0; i < ITERATIONS; i++) {
synchronized (threadLocal) {
//Although accessing a static field, we get our own (previously saved) value.
int value = threadLocal.get();
System.out.println(Thread.currentThread().getName() + ": " + value);
//Update our own variable
threadLocal.set(value + 1);
try {
threadLocal.notifyAll();
if (i < ITERATIONS - 1) {
threadLocal.wait();
}
} catch (InterruptedException ex) {
}
}
}
}
}
Desde la salida podemos ver que cada hilo cuenta por sí mismo y no usa el valor del otro:
Thread 1: 0
Thread 2: 0
Thread 1: 1
Thread 2: 1
Thread 1: 2
Thread 2: 2
Thread 1: 3
Thread 2: 3
Thread 1: 4
Thread 2: 4
Thread 1: 5
Thread 2: 5
Thread 1: 6
Thread 2: 6
Thread 1: 7
Thread 2: 7
Thread 1: 8
Thread 2: 8
Thread 1: 9
Thread 2: 9