天天看點

Java ThreadLocal示例及使用方法總結

一、概述

ThreadLocal的名稱比較容易讓人誤解,會認為其是一個“本地線程”。其實,ThreadLocal并不是一個Thread,而是Thread的局部變量。

其設計的初衷是為了解決多線程程式設計中的資源共享問題。提起這個,大家一般會想到synchronized,synchronized采取的是“以時間換空間”的政策,本質上是對關鍵資源上鎖,讓大家排隊操作。而ThreadLocal采取的是“以空間換時間”的思路,為每個使用該變量的線程提供獨立的變量副本,在本線程内部,它相當于一個“全局變量”,可以保證本線程任何時間操縱的都是同一個對象。

 二、執行個體

下面用一個執行個體闡述ThreadLocal的使用方法

建立一個Context類,其中含有transactionId屬性。 

Java ThreadLocal示例及使用方法總結

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 }      
Java ThreadLocal示例及使用方法總結

建立MyThreadLocal做為容器,将一個Context對象儲存于ThreadLocal中

Java ThreadLocal示例及使用方法總結
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 }      
Java ThreadLocal示例及使用方法總結

多線程用戶端程式,用于測試

Java ThreadLocal示例及使用方法總結
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     }      
Java ThreadLocal示例及使用方法總結

模拟業務層,在某處讀取context對象

Java ThreadLocal示例及使用方法總結
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 }      
Java ThreadLocal示例及使用方法總結

程式輸出:

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通路相應資料,即可保證每個線程通路的是自己獨立的變量