Exemplo de Java ThreadLocal

O Java ThreadLocal é usado para criar variáveis locais de thread. Sabemos que todas as threads de um Objeto compartilham suas variáveis, portanto, a variável não é segura para thread. Podemos usar sincronização para segurança da thread, mas se quisermos evitar a sincronização, podemos usar variáveis ThreadLocal.

Java ThreadLocal

Cada thread tem sua própria variável ThreadLocal e elas podem usar seus métodos get() e set() para obter o valor padrão ou alterar seu valor local para Thread. As instâncias de ThreadLocal são geralmente campos estáticos privados em classes que desejam associar um estado a uma thread.

Exemplo de Java ThreadLocal

Aqui está um pequeno exemplo mostrando o uso de ThreadLocal em um programa java e provando que cada thread tem sua própria cópia da variável ThreadLocal. ThreadLocalExample.java

package com.journaldev.threads;

import java.text.SimpleDateFormat;
import java.util.Random;

public class ThreadLocalExample implements Runnable{

    // SimpleDateFormat não é seguro para thread, então dê um para cada thread
    private static final ThreadLocal formatter = new ThreadLocal(){
        @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();
        }
        //o padrão do formatador é alterado aqui pela thread, mas isso não será refletido em outras threads
        formatter.set(new SimpleDateFormat());
        
        System.out.println("Thread Name= "+Thread.currentThread().getName()+" formatter = "+formatter.get().toPattern());
    }

}

A saída do programa de exemplo Java ThreadLocal acima é:

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 você pode ver a partir da saída, o Thread-0 alterou o valor do formatador, mas ainda assim o formatador padrão do Thread-2 permanece o mesmo que o valor inicializado. Você pode observar o mesmo padrão para os outros threads também. Atualização: A classe ThreadLocal foi estendida no Java 8 com um novo método withInitial() que recebe como argumento a interface funcional Supplier. Assim, podemos usar expressões lambda para criar facilmente a instância ThreadLocal. Por exemplo, a variável ThreadLocal do formatador acima pode ser definida em uma linha da seguinte forma:

private static final ThreadLocal<SimpleDateFormat> formatter = 
	ThreadLocal.<SimpleDateFormat>withInitial
	(() -> {return new SimpleDateFormat("yyyyMMdd HHmm");});

Se você é novo nas funcionalidades do Java 8, por favor, confira Recursos do Java 8 e Interfaces Funcionais do Java 8. Isso é tudo sobre o ThreadLocal na programação Java. Referência: Documentação da API

Source:
https://www.digitalocean.com/community/tutorials/java-threadlocal-example