JDK提供了ThreadLocal,在一個線程中傳遞同一個對象,相當於保存一個線程的局部變量。
基本使用流程
// 創建ThreadLocal對象
static ThreadLocal<String> threadLocalUser = new ThreadLocal<>();
// 保存對象
threadLocalUser.set("Bob");
// 獲取對象
String current = threadLocalUser.get();
// 移除對象
threadLocalUser.remove();
典型使用方式
void processUser(user) {
try {
// 保存user對象
threadLocalUser.set(user);
// 進行傳遞
step1();
} finally {
// 保證最後移除,因爲線程可能用完後可能會被放進線程池繼續使用
threadLocalUser.remove();
}
}
void step1() {
// 上面保存的user被存在線程中
// 通過ThreadLocal來獲取
User u = threadLocalUser.get();
log(u.name);
// 繼續傳遞
printUser();
}
void printUser() {
// 同樣可以獲取ThreadLocal保存的user對象
User u = threadLocalUser.get();
println(u.name);
}
案例分析
// 簡單用戶信息類
class User {
Stirng name;
int level;
public User(String name, int level) {
this.name = name;
this.level = level;
}
}
// 封裝適用於User對象的ThreadLocal
class UserContext implements AutoCloseable {
// 全局唯一靜態變量
static final ThreadLocal<User> context = new ThreadLocal<>();
// 獲取當前線程的ThreadLocal User
public static User getCurrentUser() {
return context.get();
}
// 初始化ThreadLocal的User
public UserContext(User user) {
context.set(user);
}
// 移除ThreadLocal關聯的User
public void close() {
context.remove();
}
}
class ProcessThread extends Thread {
User user;
ProcessThread(User user) {
this.user = user;
}
@Override
public void run() {
// 創建對象
try(UserContext ctx = new UserContext(user)) {
// step1 測試傳遞結果
new Greeting().hello();
// step2 測試傳遞結果
Level.checkLevel();
}
}
}
class Greeting {
void hello() {
User user = Usercontext.getCurrentUser();
System.out.println("Hello, " + user.name);
}
}
class Level {
static void checkLevel {
User user = UserContext.getCurrentUser();
if(user.level > 100) {
System.out.println(user.name + " is a VIP user.");
} else {
System.out.println(user.name + " is a registered user.");
}
}
}
public class Main {
public static void main(String[] args) {
Thread t1 = new ProcessThread(new User("Bob", 120));
Thread t2 = new ProcessThread(new User("Alice", 80));
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("Main end");
}
}
總結
可以把ThreadLocal看成全局Map<Thread, Object>:
- 每個線程獲取ThreadLocal變量時,使用Thread自身作爲key:
Object threadLocalValue = threadLocalMap.get(Thread.currentThread());
- ThreadLocal表示線程的“局部變量”, 它確保每個線程的ThreadLocal變量都是各自獨立的。
- ThreadLocal適合在一個線程的處理流程中保持上下文(避免了同一參數在所有方法中傳遞)
- 使用ThreadLocal要用try … finally結構