Java Language
ThreadLocal
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