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结构