Ricerca…


Osservazioni

Ideale per oggetti che dipendono da internals durante il richiamo di una chiamata, ma altrimenti sono stateless, come SimpleDateFormat , Marshaller

Per l'utilizzo di ThreadLocal Random , prendere in considerazione l'utilizzo di ThreadLocalRandom

Inizializzazione funzionale di Java 8 ThreadLocal

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);
    }
}

Utilizzo thread di base

Java ThreadLocal è usato per creare variabili locali del thread. È noto che i thread di un oggetto condividono le sue variabili, quindi la variabile non è thread-safe. Possiamo usare la sincronizzazione per la sicurezza dei thread, ma se vogliamo evitare la sincronizzazione, ThreadLocal ci permette di creare variabili che sono locali al thread, cioè solo che quel thread può leggere o scrivere su quelle variabili, quindi gli altri thread eseguono lo stesso pezzo di codice non sarà in grado di accedere alle altre variabili ThreadLocal.

Questo può essere usato possiamo usare variabili ThreadLocal . in situazioni in cui si dispone di un pool di thread, ad esempio in un servizio Web. Ad esempio, la creazione di un oggetto SimpleDateFormat ogni volta per ogni richiesta richiede molto tempo e non è possibile creare uno statico in quanto SimpleDateFormat non è thread-safe, quindi possiamo creare un ThreadLocal in modo da poter eseguire operazioni thread-safe senza l'overhead di creare SimpleDateFormat ogni tempo.

Il seguente codice mostra come può essere usato:

Ogni thread ha la propria variabile ThreadLocal e possono usare i suoi metodi get() e set() per ottenere il valore predefinito o cambiarne il valore local in Thread.

ThreadLocal istanze ThreadLocal sono in genere campi statici privati ​​in classi che desiderano associare lo stato a un thread.

Ecco un piccolo esempio che mostra l'uso di ThreadLocal nel programma java e dimostra che ogni thread ha la propria copia della variabile 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());
    }

}

Produzione:

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

Come possiamo vedere dall'output, Thread-0 ha cambiato il valore di formattatore, ma il formattatore di default di thread-2 è lo stesso del valore inizializzato.

Più thread con un oggetto condiviso

In questo esempio abbiamo un solo oggetto ma è condiviso tra / eseguito su thread differenti. L'uso normale dei campi per salvare lo stato non sarebbe possibile perché anche l'altro thread lo vedrebbe (o probabilmente non vedrebbe).

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();
    }
}

In Foo contiamo partendo da zero. Invece di salvare lo stato in un campo, memorizziamo il nostro numero corrente nell'oggetto ThreadLocal che è staticamente accessibile. Si noti che la sincronizzazione in questo esempio non è correlata all'utilizzo di ThreadLocal ma assicura un output della console migliore.

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) {
                }
            }
        }
    }
}

Dall'output possiamo vedere che ogni thread conta per se stesso e non usa il valore dell'altro:

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


Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow