一、概述
ThreadLocal的名稱比較容易讓人誤解,會認為其是一個“本地線程”。其實,ThreadLocal并不是一個Thread,而是Thread的局部變量。
其設計的初衷是為了解決多線程程式設計中的資源共享問題。提起這個,大家一般會想到synchronized,synchronized采取的是“以時間換空間”的政策,本質上是對關鍵資源上鎖,讓大家排隊操作。而ThreadLocal采取的是“以空間換時間”的思路,為每個使用該變量的線程提供獨立的變量副本,在本線程内部,它相當于一個“全局變量”,可以保證本線程任何時間操縱的都是同一個對象。
二、執行個體
下面用一個執行個體闡述ThreadLocal的使用方法
建立一個Context類,其中含有transactionId屬性。
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsISPrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdsATOfd3bkFGazxCMx8VesATMfhHLlN3XnxCMwEzX0xiRGZkRGZ0Xy9GbvNGLpZTY1EmMZVDUSFTU4VFRR9Fd4VGdsYTMfVmepNHLrJXYtJXZ0F2dvwVZnFWbp1zczV2YvJHctM3cv1Ce-YWan5yNiBDNmVGZldjY5ETMzUGO4QmN4IGN0ImMlJzY4gjM08CXyAzLchDMxIDMy8CXn9Gbi9CXzV2Zh1WavwVbvNmLvR3YxUjL2M3Lc9CX6MHc0RHaiojIsJye.gif)
1 package com.vigar;
2
3 public class Context {
4
5 private String transactionId = null;
6
7 public String getTransactionId() {
8 return transactionId;
9 }
10
11 public void setTransactionId(String transactionId) {
12 this.transactionId = transactionId;
13 }
14 }
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsISPrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdsATOfd3bkFGazxCMx8VesATMfhHLlN3XnxCMwEzX0xiRGZkRGZ0Xy9GbvNGLpZTY1EmMZVDUSFTU4VFRR9Fd4VGdsYTMfVmepNHLrJXYtJXZ0F2dvwVZnFWbp1zczV2YvJHctM3cv1Ce-YWan5yNiBDNmVGZldjY5ETMzUGO4QmN4IGN0ImMlJzY4gjM08CXyAzLchDMxIDMy8CXn9Gbi9CXzV2Zh1WavwVbvNmLvR3YxUjL2M3Lc9CX6MHc0RHaiojIsJye.gif)
建立MyThreadLocal做為容器,将一個Context對象儲存于ThreadLocal中
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsISPrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdsATOfd3bkFGazxCMx8VesATMfhHLlN3XnxCMwEzX0xiRGZkRGZ0Xy9GbvNGLpZTY1EmMZVDUSFTU4VFRR9Fd4VGdsYTMfVmepNHLrJXYtJXZ0F2dvwVZnFWbp1zczV2YvJHctM3cv1Ce-YWan5yNiBDNmVGZldjY5ETMzUGO4QmN4IGN0ImMlJzY4gjM08CXyAzLchDMxIDMy8CXn9Gbi9CXzV2Zh1WavwVbvNmLvR3YxUjL2M3Lc9CX6MHc0RHaiojIsJye.gif)
1 package com.vigar;
2
3 public class MyThreadLocal {
4 public static final ThreadLocal userThreadLocal = new ThreadLocal();
5 public static void set(Context user) {
6 userThreadLocal.set(user);
7 }
8
9 public static void unset() {
10 userThreadLocal.remove();
11 }
12
13 public static Context get() {
14 return (Context)userThreadLocal.get();
15 }
16 }
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsISPrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdsATOfd3bkFGazxCMx8VesATMfhHLlN3XnxCMwEzX0xiRGZkRGZ0Xy9GbvNGLpZTY1EmMZVDUSFTU4VFRR9Fd4VGdsYTMfVmepNHLrJXYtJXZ0F2dvwVZnFWbp1zczV2YvJHctM3cv1Ce-YWan5yNiBDNmVGZldjY5ETMzUGO4QmN4IGN0ImMlJzY4gjM08CXyAzLchDMxIDMy8CXn9Gbi9CXzV2Zh1WavwVbvNmLvR3YxUjL2M3Lc9CX6MHc0RHaiojIsJye.gif)
多線程用戶端程式,用于測試
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsISPrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdsATOfd3bkFGazxCMx8VesATMfhHLlN3XnxCMwEzX0xiRGZkRGZ0Xy9GbvNGLpZTY1EmMZVDUSFTU4VFRR9Fd4VGdsYTMfVmepNHLrJXYtJXZ0F2dvwVZnFWbp1zczV2YvJHctM3cv1Ce-YWan5yNiBDNmVGZldjY5ETMzUGO4QmN4IGN0ImMlJzY4gjM08CXyAzLchDMxIDMy8CXn9Gbi9CXzV2Zh1WavwVbvNmLvR3YxUjL2M3Lc9CX6MHc0RHaiojIsJye.gif)
1 package com.vigar;
2
3 import java.util.Random;
4
5 public class ThreadLocalDemo extends Thread {
6
7 public static void main(String[] args) {
8 Thread threadOne = new ThreadLocalDemo();
9 threadOne.start();
10 Thread threadTwo = new ThreadLocalDemo();
11 threadTwo.start();
12 }
13
14 @Override
15 public void run() {
16 // 線程
17 Context context = new Context();
18 Random random = new Random();
19 int age = random.nextInt(100);
20 context.setTransactionId(String.valueOf(age));
21
22 System.out.println("set thread ["+getName()+"] contextid to " + String.valueOf(age));
23 // 在ThreadLocal中設定context
24 MyThreadLocal.set(context);
25 /* note that we are not explicitly passing the transaction id */
26 try {
27 Thread.sleep(1000);
28 } catch (InterruptedException e)
29 {
30 e.printStackTrace();
31 }
32
33 new BusinessService().businessMethod();
34 MyThreadLocal.unset();
35 }
36 }
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsISPrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdsATOfd3bkFGazxCMx8VesATMfhHLlN3XnxCMwEzX0xiRGZkRGZ0Xy9GbvNGLpZTY1EmMZVDUSFTU4VFRR9Fd4VGdsYTMfVmepNHLrJXYtJXZ0F2dvwVZnFWbp1zczV2YvJHctM3cv1Ce-YWan5yNiBDNmVGZldjY5ETMzUGO4QmN4IGN0ImMlJzY4gjM08CXyAzLchDMxIDMy8CXn9Gbi9CXzV2Zh1WavwVbvNmLvR3YxUjL2M3Lc9CX6MHc0RHaiojIsJye.gif)
模拟業務層,在某處讀取context對象
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsISPrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdsATOfd3bkFGazxCMx8VesATMfhHLlN3XnxCMwEzX0xiRGZkRGZ0Xy9GbvNGLpZTY1EmMZVDUSFTU4VFRR9Fd4VGdsYTMfVmepNHLrJXYtJXZ0F2dvwVZnFWbp1zczV2YvJHctM3cv1Ce-YWan5yNiBDNmVGZldjY5ETMzUGO4QmN4IGN0ImMlJzY4gjM08CXyAzLchDMxIDMy8CXn9Gbi9CXzV2Zh1WavwVbvNmLvR3YxUjL2M3Lc9CX6MHc0RHaiojIsJye.gif)
1 package com.vigar;
2 public class BusinessService {
3 public void businessMethod() {
4 Context context = MyThreadLocal.get();
5 System.out.println(context.getTransactionId());
6 }
7 }
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsISPrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdsATOfd3bkFGazxCMx8VesATMfhHLlN3XnxCMwEzX0xiRGZkRGZ0Xy9GbvNGLpZTY1EmMZVDUSFTU4VFRR9Fd4VGdsYTMfVmepNHLrJXYtJXZ0F2dvwVZnFWbp1zczV2YvJHctM3cv1Ce-YWan5yNiBDNmVGZldjY5ETMzUGO4QmN4IGN0ImMlJzY4gjM08CXyAzLchDMxIDMy8CXn9Gbi9CXzV2Zh1WavwVbvNmLvR3YxUjL2M3Lc9CX6MHc0RHaiojIsJye.gif)
程式輸出:
set thread [Thread-0] contextid to 32
set thread [Thread-1] contextid to 89
32
89
三、總結
ThreadLocal使用步驟
1.建立ThreadLocal容器對象A,其中對需要儲存的屬性進行封裝。并提供相應的get/set方法(全部為static)
2.在用戶端程式中,用A.setxxx, A.getXXX通路相應資料,即可保證每個線程通路的是自己獨立的變量