Sök…


Anmärkningar

Används bäst för objekt som är beroende av interna under påkallning av ett samtal, men är statslösa annars, som SimpleDateFormat , Marshaller

För Random ThreadLocal-användning bör du överväga att använda ThreadLocalRandom

ThreadLocal Java 8-funktionell initialisering

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

Grundläggande ThreadLocal-användning

Java ThreadLocal används för att skapa lokala trådvariabler. Det är känt att trådar av ett objekt delar sina variabler, så variabeln är inte trådsäker. Vi kan använda synkronisering för gängesäkerhet men om vi vill undvika synkronisering tillåter ThreadLocal oss att skapa variabler som är lokala för tråden, dvs bara den tråden kan läsa eller skriva till de variablerna, så de andra trådarna som kör samma kod kommer inte att kunna komma åt varandras ThreadLocal-variabler.

Detta kan användas vi kan använda ThreadLocal variabler. i situationer där du har en trådpool som till exempel i en webbtjänst. Till exempel, att skapa ett SimpleDateFormat objekt varje gång för varje begäran är tidskrävande och ett statiskt kan inte skapas eftersom SimpleDateFormat inte är trådsäker, så vi kan skapa en trådlokal så att vi kan utföra trådsäkra operationer utan överhuvudet att skapa SimpleDateFormat varje tid.

Nedanstående kod visar hur den kan användas:

Varje tråd har sin egen ThreadLocal variabel och de kan använda metoderna get() och set() att få standardvärdet eller ändra det värde som är lokalt för Thread.

ThreadLocal instanser är vanligtvis privata statiska fält i klasser som vill koppla tillstånd till en tråd.

Här är ett litet exempel som visar användning av ThreadLocal i java-program och bevisar att varje tråd har sin egen kopia av ThreadLocal variabeln.

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

}

Produktion:

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

Som vi kan se från utgången att tråd-0 har ändrat värdet på formaterare men ändå är standard-formatering thread-2 densamma som det initialiserade värdet.

Flera trådar med ett delat objekt

I det här exemplet har vi bara ett objekt men det delas mellan / körs på olika trådar. Vanlig användning av fält för att spara tillstånd skulle inte vara möjlig eftersom den andra tråden skulle se det också (eller förmodligen inte se).

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

I Foo räknar vi från noll. I stället för att spara tillståndet i ett fält lagrar vi vårt nuvarande nummer i ThreadLocal-objektet som är statiskt tillgängligt. Observera att synkroniseringen i detta exempel inte är relaterad till användningen av ThreadLocal utan snarare säkerställer en bättre konsolutgång.

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

Från utgången kan vi se att varje tråd räknar sig själv och inte använder värdet på den andra:

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
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow