Java ThreadLocal 用于创建线程本地变量,我们知道一个对象的所有线程都共享它的变量,所以变量不是线程安全的,我们可以使用同步来确保线程安全,但如果我们想要避免同步,我们可以使用‘ThreadLocal’变量。
Java ThreadLocal 应用程序
Every thread has it's own
ThreadLocal
variable and they can use it's get() and set() methods to get the default value or change it's value local to Thread. ThreadLocal instances are typically private static fields in classes that wish to associate state with a thread.
Java ThreadLocal 示例
以下是一個小例子,顯示了 Java 程式中 ThreadLocal 的使用,並證明每個 thread 都有其自己的 ThreadLocal 變數副本。
1package com.journaldev.threads;
2
3import java.text.SimpleDateFormat;
4import java.util.Random;
5
6public class ThreadLocalExample implements Runnable{
7
8 // SimpleDateFormat is not thread-safe, so give one to each thread
9 private static final ThreadLocal<SimpleDateFormat> formatter = new ThreadLocal<SimpleDateFormat>(){
10 @Override
11 protected SimpleDateFormat initialValue()
12 {
13 return new SimpleDateFormat("yyyyMMdd HHmm");
14 }
15 };
16
17 public static void main(String[] args) throws InterruptedException {
18 ThreadLocalExample obj = new ThreadLocalExample();
19 for(int i=0 ; i<10; i++){
20 Thread t = new Thread(obj, ""+i);
21 Thread.sleep(new Random().nextInt(1000));
22 t.start();
23 }
24 }
25
26 @Override
27 public void run() {
28 System.out.println("Thread Name= "+Thread.currentThread().getName()+" default Formatter = "+formatter.get().toPattern());
29 try {
30 Thread.sleep(new Random().nextInt(1000));
31 } catch (InterruptedException e) {
32 e.printStackTrace();
33 }
34 //formatter pattern is changed here by thread, but it won't reflect to other threads
35 formatter.set(new SimpleDateFormat());
36
37 System.out.println("Thread Name= "+Thread.currentThread().getName()+" formatter = "+formatter.get().toPattern());
38 }
39
40}
上面的 Java ThreadLocal 示例程序的输出是:
1Thread Name= 0 default Formatter = yyyyMMdd HHmm
2Thread Name= 1 default Formatter = yyyyMMdd HHmm
3Thread Name= 0 formatter = M/d/yy h:mm a
4Thread Name= 2 default Formatter = yyyyMMdd HHmm
5Thread Name= 1 formatter = M/d/yy h:mm a
6Thread Name= 3 default Formatter = yyyyMMdd HHmm
7Thread Name= 4 default Formatter = yyyyMMdd HHmm
8Thread Name= 4 formatter = M/d/yy h:mm a
9Thread Name= 5 default Formatter = yyyyMMdd HHmm
10Thread Name= 2 formatter = M/d/yy h:mm a
11Thread Name= 3 formatter = M/d/yy h:mm a
12Thread Name= 6 default Formatter = yyyyMMdd HHmm
13Thread Name= 5 formatter = M/d/yy h:mm a
14Thread Name= 6 formatter = M/d/yy h:mm a
15Thread Name= 7 default Formatter = yyyyMMdd HHmm
16Thread Name= 8 default Formatter = yyyyMMdd HHmm
17Thread Name= 8 formatter = M/d/yy h:mm a
18Thread Name= 7 formatter = M/d/yy h:mm a
19Thread Name= 9 default Formatter = yyyyMMdd HHmm
20Thread Name= 9 formatter = M/d/yy h:mm a
正如你可以从输出中看到的那样,Thread-0 已经改变了 formater 的值,但 thread-2 默认的 formater 与初始化值相同。 您也可以看到其他 threads 的相同模式。 Update:ThreadLocal 类在 Java 8 中被扩展到一种新的方法 withInitial()
,该方法将供应商的功能界面作为论点。 因此,我们可以使用 lambda 表达式来轻松创建 ThreadLocal 实例。
1private static final ThreadLocal<SimpleDateFormat> formatter =
2 ThreadLocal.<SimpleDateFormat>withInitial
3 (() -> {return new SimpleDateFormat("yyyyMMdd HHmm");});
如果您对 Java 8 功能不熟悉,请参阅 [Java 8 Features](/community/tutorials/java-8-features-with-examples Java 8 Features
)和 [Java 8 Functional Interfaces](/community/tutorials/java-8-functional-interfaces Java 8 Functional Interfaces
)。