Pergunta

Quando devo usar um ThreadLocal variável?

Como isso é usado?

Foi útil?

Solução

Um uso possível (e comum) é quando você tem algum objeto que não é seguro para fios, mas você quer evitar sincronizando acesso a esse objeto (estou olhando para você, SimpledateFormat). Em vez disso, dê a cada tópico sua própria instância do objeto.

Por exemplo:

public class Foo
{
    // 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 String formatIt(Date date)
    {
        return formatter.get().format(date);
    }
}

Documentação.

Outras dicas

Desde uma ThreadLocal é uma referência aos dados dentro de um dado Thread, você pode acabar com vazamentos de carga de classe ao usar ThreadLocals em servidores de aplicativos usando pools de threads. Você precisa ter muito cuidado para limpar qualquer ThreadLocalvocê get() ou set() usando o ThreadLocal's remove() método.

Se você não limpar quando terminar, quaisquer referências que se mantenham às aulas carregadas como parte de um webApp implantado permanecerá no heap permanente e nunca receberá lixo coletado. Reimplementar/não implantar o webApp não limpará cada Threadreferência às classes do seu WebApp, já que o Thread não é algo de propriedade do seu webapp. Cada implantação sucessiva criará uma nova instância da classe que nunca será coletada de lixo.

Você acabará com exceções fora da memória devido a java.lang.OutOfMemoryError: PermGen space e depois de pesquisar no Google provavelmente apenas aumentará -XX:MaxPermSize Em vez de consertar o bug.

Se você acabar enfrentando esses problemas, poderá determinar qual tópico e classe estão mantendo essas referências usando Analisador de memória do Eclipse e/ou seguindo Guia de Frank Kieviet e acompanhamento.

Atualização: redescoberto A entrada do blog de Alex Vasseur Isso me ajudou a rastrear alguns ThreadLocal questões que eu estava tendo.

Muitas estruturas usam ThreadLocals para manter algum contexto relacionado ao thread atual.Por exemplo, quando a transação atual é armazenada em um ThreadLocal, você não precisa passá-la como parâmetro em todas as chamadas de método, caso alguém na pilha precise acessá-la.Os aplicativos da Web podem armazenar informações sobre a solicitação e a sessão atuais em um ThreadLocal, para que o aplicativo tenha acesso fácil a eles.Com Guice você pode usar ThreadLocals ao implementar escopos personalizados para os objetos injetados (padrão do Guice escopos de servlet provavelmente também os use).

ThreadLocals são um tipo de variáveis ​​globais (embora um pouco menos prejudiciais porque são restritas a um thread), portanto, você deve ter cuidado ao usá-las para evitar efeitos colaterais indesejados e vazamentos de memória.Projete suas APIs para que os valores ThreadLocal sejam sempre limpos automaticamente quando não forem mais necessários e para que o uso incorreto da API não seja possível (por exemplo assim).ThreadLocals podem ser usados ​​para tornar o código mais limpo e, em alguns casos raros, são a única maneira de fazer algo funcionar (meu projeto atual teve dois casos desse tipo;eles são documentados aqui em "Campos estáticos e variáveis ​​globais").

Em Java, se você tiver um dado que possa variar por thread, suas opções devem passar esse dado para todos os métodos que precisam (ou podem precisar) ou associar o dado ao thread. Passar o dado em todos os lugares pode ser viável se todos os seus métodos já precisarem transmitir uma variável "contexto" comum.

Se não for esse o caso, talvez você não queira confundir as assinaturas de método com um parâmetro adicional. Em um mundo não thread, você pode resolver o problema com o equivalente a Java de uma variável global. Em uma palavra rosqueada, o equivalente a uma variável global é uma variável local de rosca.

Há um exemplo muito bom no livro Simultaneidade Java na prática.Onde o autor (Josué Bloch) explica como o confinamento de thread é uma das maneiras mais simples de obter segurança de thread e ThreadLocal é um meio mais formal de manter o confinamento do thread.No final, ele também explica como as pessoas podem abusar dela, usando-a como variáveis ​​globais.

Copiei o texto do livro mencionado, mas falta o código 3.10, pois não é muito importante entender onde o ThreadLocal deve ser usado.

Variáveis ​​locais de thread são frequentemente usadas para evitar o compartilhamento em designs baseados em Singletons mutáveis ​​ou variáveis ​​globais.Por exemplo, um aplicativo de thread único pode manter uma conexão de banco de dados global que é inicializada na inicialização para evitar a necessidade de passar uma conexão para todos os métodos.Como as conexões JDBC podem não ser seguras para threads, um aplicativo multithread que usa uma conexão global sem coordenação adicional também não é seguro para threads.Ao usar um ThreadLocal para armazenar a conexão JDBC, como em ConnectionHolder na Listagem 3.10, cada thread terá sua própria conexão.

ThreadLocal é amplamente utilizado na implementação de estruturas de aplicativos.Por exemplo, os contêineres J2EE associam um contexto de transação a um encadeamento em execução durante uma chamada EJB.Isso é facilmente implementado usando um Thread-Local estático que contém o contexto da transação:quando o código da estrutura precisa determinar qual transação está em execução no momento, ele busca o contexto da transação neste ThreadLocal.Isso é conveniente porque reduz a necessidade de passar informações de contexto de execução para cada método, mas acopla qualquer código que use esse mecanismo à estrutura.

É fácil abusar do ThreadLocal tratando sua propriedade de confinamento de thread como uma licença para usar variáveis ​​globais ou como um meio de criar argumentos de método “ocultos”.Assim como as variáveis ​​globais, as variáveis ​​locais de thread podem prejudicar a capacidade de reutilização e introduzir acoplamentos ocultos entre classes e, portanto, devem ser usadas com cuidado.

Essencialmente, quando você precisa de um valor da variável para depender do fio atual e isso não é conveniente para você anexar o valor ao tópico de outra maneira (Por exemplo, thread de subclassificação).

Um caso típico é onde Alguma outra estrutura criou o tópico que seu código está sendo executado, por exemplo, um contêiner de servlet ou onde faz mais sentido usar o Threadlocal porque sua variável está então "em seu lugar lógico" (em vez de uma variável pendurada em uma subclasse de rosca ou em algum outro mapa de hash) .

No meu site, eu tenho mais alguns discussão e exemplos de quando usar o Threadlocal Isso também pode ser de interesse.

Algumas pessoas defendem o uso do Threadlocal como uma maneira de anexar um "ID do thread" a cada thread em certos algoritmos simultâneos, onde você precisa de um número de thread (consulte EG Herlihy & Shavit). Nesses casos, verifique se você está realmente recebendo um benefício!

The documentation says it very well: "each thread that accesses [a thread-local variable] (via its get or set method) has its own, independently initialized copy of the variable".

You use one when each thread must have its own copy of something. By default, data is shared between threads.

Webapp server may keep a thread pool, and a ThreadLocal var should be removed before response to the client, thus current thread may be reused by next request.

  1. ThreadLocal in Java had been introduced on JDK 1.2 but was later generified in JDK 1.5 to introduce type safety on ThreadLocal variable.

  2. ThreadLocal can be associated with Thread scope, all the code which is executed by Thread has access to ThreadLocal variables but two thread can not see each others ThreadLocal variable.

  3. Each thread holds an exclusive copy of ThreadLocal variable which becomes eligible to Garbage collection after thread finished or died, normally or due to any Exception, Given those ThreadLocal variable doesn't have any other live references.

  4. ThreadLocal variables in Java are generally private static fields in Classes and maintain its state inside Thread.

Read more: ThreadLocal in Java - Example Program and Tutorial

Two use cases where threadlocal variable can be used -
1- When we have a requirement to associate state with a thread (e.g., a user ID or Transaction ID). That usually happens with a web application that every request going to a servlet has a unique transactionID associated with it.

// This class will provide a thread local variable which
// will provide a unique ID for each thread
class ThreadId {
    // Atomic integer containing the next thread ID to be assigned
    private static final AtomicInteger nextId = new AtomicInteger(0);

    // Thread local variable containing each thread's ID
    private static final ThreadLocal<Integer> threadId =
        ThreadLocal.<Integer>withInitial(()-> {return nextId.getAndIncrement();});

    // Returns the current thread's unique ID, assigning it if necessary
    public static int get() {
        return threadId.get();
    }
}

Note that here the method withInitial is implemented using lambda expression.
2- Another use case is when we want to have a thread safe instance and we don't want to use synchronization as the performance cost with synchronization is more. One such case is when SimpleDateFormat is used. Since SimpleDateFormat is not thread safe so we have to provide mechanism to make it thread safe.

public class ThreadLocalDemo1 implements Runnable {
    // threadlocal variable is created
    private static final ThreadLocal<SimpleDateFormat> dateFormat = new ThreadLocal<SimpleDateFormat>(){
        @Override
        protected SimpleDateFormat initialValue(){
            System.out.println("Initializing SimpleDateFormat for - " + Thread.currentThread().getName() );
            return new SimpleDateFormat("dd/MM/yyyy");
        }
    };

    public static void main(String[] args) {
        ThreadLocalDemo1 td = new ThreadLocalDemo1();
        // Two threads are created
        Thread t1 = new Thread(td, "Thread-1");
        Thread t2 = new Thread(td, "Thread-2");
        t1.start();
        t2.start();
    }

    @Override
    public void run() {
        System.out.println("Thread run execution started for " + Thread.currentThread().getName());
        System.out.println("Date formatter pattern is  " + dateFormat.get().toPattern());
        System.out.println("Formatted date is " + dateFormat.get().format(new Date()));
    } 

}

Since Java 8 release, there is more declarative way to initialize ThreadLocal:

ThreadLocal<Cipher> local = ThreadLocal.withInitial(() -> "init value");

Until Java 8 release you had to do the following:

ThreadLocal<String> local = new ThreadLocal<String>(){
    @Override
    protected String initialValue() {
        return "init value";
    }
};

Moreover, if instantiation method (constructor, factory method) of class that is used for ThreadLocal does not take any parameters, you can simply use method references (introduced in Java 8):

class NotThreadSafe {
    // no parameters
    public NotThreadSafe(){}
}

ThreadLocal<NotThreadSafe> container = ThreadLocal.withInitial(NotThreadSafe::new);

Note: Evaluation is lazy since you are passing java.util.function.Supplier lambda that is evaluated only when ThreadLocal#get is called but value was not previously evaluated.

You have to be very careful with the ThreadLocal pattern. There are some major down sides like Phil mentioned, but one that wasn't mentioned is to make sure that the code that sets up the ThreadLocal context isn't "re-entrant."

Bad things can happen when the code that sets the information gets run a second or third time because information on your thread can start to mutate when you didn't expect it. So take care to make sure the ThreadLocal information hasn't been set before you set it again.

when?

When an object is not thread-safe, instead of synchronization which hampers the scalability, give one object to every thread and keep it thread scope, which is ThreadLocal. One of most often used but not thread-safe objects are database Connection and JMSConnection.

How ?

One example is Spring framework uses ThreadLocal heavily for managing transactions behind the scenes by keeping these connection objects in ThreadLocal variables. At high level, when a transaction is started it gets the connection ( and disables the auto commit ) and keeps it in ThreadLocal. on further db calls it uses same connection to communicate with db. At the end, it takes the connection from ThreadLocal and commits ( or rollback ) the transaction and releases the connection.

I think log4j also uses ThreadLocal for maintaining MDC.

ThreadLocal is useful, when you want to have some state that should not be shared amongst different threads, but it should be accessible from each thread during its whole lifetime.

As an example, imagine a web application, where each request is served by a different thread. Imagine that for each request you need a piece of data multiple times, which is quite expensive to compute. However, that data might have changed for each incoming request, which means that you can't use a plain cache. A simple, quick solution to this problem would be to have a ThreadLocal variable holding access to this data, so that you have to calculate it only once for each request. Of course, this problem can also be solved without the use of ThreadLocal, but I devised it for illustration purposes.

That said, have in mind that ThreadLocals are essentially a form of global state. As a result, it has many other implications and should be used only after considering all the other possible solutions.

Nothing really new here, but I discovered today that ThreadLocal is very useful when using Bean Validation in a web application. Validation messages are localized, but by default use Locale.getDefault(). You can configure the Validator with a different MessageInterpolator, but there's no way to specify the Locale when you call validate. So you could create a static ThreadLocal<Locale> (or better yet, a general container with other things you might need to be ThreadLocal and then have your custom MessageInterpolator pick the Locale from that. Next step is to write a ServletFilter which uses a session value or request.getLocale() to pick the locale and store it in your ThreadLocal reference.

As was mentioned by @unknown (google), it's usage is to define a global variable in which the value referenced can be unique in each thread. It's usages typically entails storing some sort of contextual information that is linked to the current thread of execution.

We use it in a Java EE environment to pass user identity to classes that are not Java EE aware (don't have access to HttpSession, or the EJB SessionContext). This way the code, which makes usage of identity for security based operations, can access the identity from anywhere, without having to explicitly pass it in every method call.

The request/response cycle of operations in most Java EE calls makes this type of usage easy since it gives well defined entry and exit points to set and unset the ThreadLocal.

ThreadLocal will ensure accessing the mutable object by the multiple threads in the non synchronized method is synchronized, means making the mutable object to be immutable within the method.

This is achieved by giving new instance of mutable object for each thread try accessing it. So It is local copy to the each thread. This is some hack on making instance variable in a method to be accessed like a local variable. As you aware method local variable is only available to the thread, one difference is; method local variables will not available to the thread once method execution is over where as mutable object shared with threadlocal will be available across multiple methods till we clean it up.

By Definition:

The ThreadLocal class in Java enables you to create variables that can only be read and written by the same thread. Thus, even if two threads are executing the same code, and the code has a reference to a ThreadLocal variable, then the two threads cannot see each other's ThreadLocal variables.

Each Thread in java contains ThreadLocalMap in it.
Where

Key = One ThreadLocal object shared across threads.
value = Mutable object which has to be used synchronously, this will be instantiated for each thread.

Achieving the ThreadLocal:

Now create a wrapper class for ThreadLocal which is going to hold the mutable object like below (with or without initialValue()).
Now getter and setter of this wrapper will work on threadlocal instance instead of mutable object.

If getter() of threadlocal didn't find any value with in the threadlocalmap of the Thread; then it will invoke the initialValue() to get its private copy with respect to the thread.

class SimpleDateFormatInstancePerThread {

    private static final ThreadLocal<SimpleDateFormat> dateFormatHolder = new ThreadLocal<SimpleDateFormat>() {

        @Override
        protected SimpleDateFormat initialValue() {
            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd") {
                UUID id = UUID.randomUUID();
                @Override
                public String toString() {
                    return id.toString();
                };
            };
            System.out.println("Creating SimpleDateFormat instance " + dateFormat +" for Thread : " + Thread.currentThread().getName());
            return dateFormat;
        }
    };

    /*
     * Every time there is a call for DateFormat, ThreadLocal will return calling
     * Thread's copy of SimpleDateFormat
     */
    public static DateFormat getDateFormatter() {
        return dateFormatHolder.get();
    }

    public static void cleanup() {
        dateFormatHolder.remove();
    }
}

Now wrapper.getDateFormatter() will call threadlocal.get() and that will check the currentThread.threadLocalMap contains this (threadlocal) instance.
If yes return the value (SimpleDateFormat) for corresponding threadlocal instance
else add the map with this threadlocal instance, initialValue().

Herewith thread safety achieved on this mutable class; by each thread is working with its own mutable instance but with same ThreadLocal instance. Means All the thread will share the same ThreadLocal instance as key, but different SimpleDateFormat instance as value.

https://github.com/skanagavelu/yt.tech/blob/master/src/ThreadLocalTest.java

Thread-local variables are often used to prevent sharing in designs based on mutable Singletons or global variables.

It can be used in scenarios like making seperate JDBC connection for each thread when you are not using a Connection Pool.

private static ThreadLocal<Connection> connectionHolder
           = new ThreadLocal<Connection>() {
      public Connection initialValue() {
           return DriverManager.getConnection(DB_URL);
          }
     };

public static Connection getConnection() {
      return connectionHolder.get();
} 

When you call getConnection, it will return a connection associated with that thread.The same can be done with other properties like dateformat, transaction context that you don't want to share between threads.

You could have also used local variables for the same, but these resource usually take up time in creation,so you don't want to create them again and again whenever you perform some business logic with them. However, ThreadLocal values are stored in the thread object itself and as soon as the thread is garbage collected, these values are gone too.

This link explains use of ThreadLocal very well.

The ThreadLocal class in Java enables you to create variables that can only be read and written by the same thread. Thus, even if two threads are executing the same code, and the code has a reference to a ThreadLocal variable, then the two threads cannot see each other's ThreadLocal variables.

Read more

[For Reference]ThreadLocal cannot solve update problems of shared object. It is recommended to use a staticThreadLocal object which is shared by all operations in the same thread. [Mandatory]remove() method must be implemented by ThreadLocal variables, especially when using thread pools in which threads are often reused. Otherwise, it may affect subsequent business logic and cause unexpected problems such as memory leak.

Caching, sometime you have to calculate the same value lots of time so by storing the last set of inputs to a method and the result you can speed the code up. By using Thread Local Storage you avoid having to think about locking.

ThreadLocal is a specially provisioned functionality by JVM to provide an isolated storage space for threads only. like the value of instance scoped variable are bound to a given instance of a class only. each object has its only values and they can not see each other value. so is the concept of ThreadLocal variables, they are local to the thread in the sense of object instances other thread except for the one which created it, can not see it. See Here

import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.IntStream;


public class ThreadId {
private static final AtomicInteger nextId = new AtomicInteger(1000);

// Thread local variable containing each thread's ID
private static final ThreadLocal<Integer> threadId = ThreadLocal.withInitial(() -> nextId.getAndIncrement());


// Returns the current thread's unique ID, assigning it if necessary
public static int get() {
    return threadId.get();
}

public static void main(String[] args) {

    new Thread(() -> IntStream.range(1, 3).forEach(i -> {
        System.out.println(Thread.currentThread().getName() + " >> " + new ThreadId().get());
    })).start();

    new Thread(() -> IntStream.range(1, 3).forEach(i -> {
        System.out.println(Thread.currentThread().getName() + " >> " + new ThreadId().get());
    })).start();

    new Thread(() -> IntStream.range(1, 3).forEach(i -> {
        System.out.println(Thread.currentThread().getName() + " >> " + new ThreadId().get());
    })).start();

}
}

Threadlocal provides a very easy way to achieve objects reusability with zero cost.

I had a situation where multiple threads were creating an image of mutable cache, on each update notification.

I used a Threadlocal on each thread, and then each thread would just need to reset old image and then update it again from the cache on each update notification.

Usual reusable objects from object pools have thread safety cost associated with them, while this approach has none.

There are 3 scenarios for using a class helper like SimpleDateFormat in multithread code, which best one is use ThreadLocal

Scenarios

1- Using like share object by the help of lock or synchronization mechanism which makes the app slow

2- Using as a local object inside a method

In this scenario, if we have 4 thread each one calls a method 1000 time then we have
4000 SimpleDateFormat object created and waiting for GC to erase them

3- Using ThreadLocal

if we have 4 thread and we gave to each thread one SimpleDateFormat instance
so we have 4 threads, 4 objects of SimpleDateFormat.

There is no need of lock mechanism and object creation and destruction. (Good time complexity and space complexity)

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top