ThreadLocal<T> 提供 線程局部變量:每個線程擁有獨立的變量副本,互不干擾。本質上是一個以 Thread 為 Key、以值為 Value 的映射,但由 Thread 內部持有 ThreadLocalMap,而非 ThreadLocal 持有 Map。
| 方法 | 說明 |
|---|---|
set(T value) | 設置當前線程的值 |
get() | 獲取當前線程的值,首次調用觸發 initialValue() |
remove() | 移除當前線程的值,防止內存洩漏 |
withInitial(Supplier<? extends T>) | Java 8+ 靜態工廠方法,簡化初始化 |
public class HibernateUtil {
private static final ThreadLocal<Session> sessionHolder =
ThreadLocal.withInitial(() -> sessionFactory.openSession());
public static Session getSession() {
return sessionHolder.get();
}
public static void closeSession() {
Session session = sessionHolder.get();
if (session != null && session.isOpen()) {
session.close();
}
sessionHolder.remove(); // 關鍵:防止內存洩漏
}
}
// Spring 內部實現簡化版
public class TransactionSynchronizationManager {
private static final ThreadLocal
public class UserContextHolder {
private static final ThreadLocal<UserPrincipal> context = new ThreadLocal<>();
public static void setUser(UserPrincipal user) {
context.set(user);
}
public static UserPrincipal getUser() {
return context.get();
}
public static void clear() {
context.remove();
}
}
// Filter 中設置
public class AuthenticationFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) {
try {
UserPrincipal user = authenticate((HttpServletRequest) req);
UserContextHolder.setUser(user);
chain.doFilter(req, res);
} finally {
UserContextHolder.clear(); // 必須清理
}
}
}
// Service 中直接獲取
@Service
public class OrderService {
public void createOrder(OrderDTO dto) {
UserPrincipal user = UserContextHolder.getUser(); // 無需參數傳遞
Order order = new Order();
order.setUserId(user.getId());
// ...
}
}
public class DateUtils {
// 每線程一個實例,避免並發解析錯誤
private static final ThreadLocal<SimpleDateFormat> dateFormat =
ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
public static String format(Date date) {
return dateFormat.get().format(date);
}
public static Date parse(String str) throws ParseException {
return dateFormat.get().parse(str);
}
}
public class TraceContext {
private static final ThreadLocal<String> traceIdHolder = new ThreadLocal<>();
private static final ThreadLocal<String> spanIdHolder = new ThreadLocal<>();
public static String getTraceId() {
String traceId = traceIdHolder.get();
if (traceId == null) {
traceId = UUID.randomUUID().toString().replace("-", "");
traceIdHolder.set(traceId);
}
return traceId;
}
public static void setTraceId(String traceId) {
traceIdHolder.set(traceId);
}
public static void clear() {
traceIdHolder.remove();
spanIdHolder.remove();
}
}
// Feign/Ribbon 攔截器傳遞
@RequestInterceptor
public class TraceFeignInterceptor implements RequestInterceptor {
public void apply(RequestTemplate template) {
template.header("X-Trace-Id", TraceContext.getTraceId());
template.header("X-Span-Id", TraceContext.getSpanId());
}
}
// ThreadLocalMap 結構簡化
static class ThreadLocalMap {
static class Entry extends WeakReference<ThreadLocal<?>> {
Object value;
Entry(ThreadLocal<?> k, Object v) { super(k); value = v; }
}
// Key 是 WeakReference,Value 是強引用
// 當 ThreadLocal 實例被 GC,Key 變 null,但 Value 仍被 Entry 引用
// 只有當線程結束或調用 remove() 時,Entry 才會被清理
}
public class ThreadLocalTemplate<T> {
private final ThreadLocal<T> holder = new ThreadLocal<>();
public void executeWith(T value, Runnable action) {
holder.set(value);
try {
action.run();
} finally {
holder.remove(); // 關鍵清理
}
}
public T get() { return holder.get(); }
public void executeWithInitial(Supplier<T> supplier, Runnable action) {
holder.set(supplier.get());
try { action.run(); } finally { holder.remove(); }
}
}
// 使用
ThreadLocalTemplate<UserPrincipal> userContext = new ThreadLocalTemplate<>();
userContext.executeWith(currentUser, () -> {
// 業務邏輯自動獲取 userContext.get()
orderService.createOrder(dto);
});
| 維度 | ThreadLocal | ConcurrentHashMap |
|---|---|---|
| 隔離性 | 線程完全隔離,無共享 | 共享數據,需同步/原子操作 |
| 適用場景 | 線程上下文、請求範圍數據 | 全局緩存、計數器、共享狀態 |
| 內存模型 | 每線程獨立副本 | 單一實例,分段/節點級鎖 |
| 生命週期 | 隨線程/手動清理 | 應用生命週期 |
| 性能 | 極高 (無鎖、無爭用) | 高 (CAS+細粒度鎖) |
// ThreadLocal.get()
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) return (T) e.value;
}
return setInitialValue(); // 首次調用初始化
}
// ThreadLocal.set()
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) map.set(this, value);
else createMap(t, value);
}
// ThreadLocalMap 線性探測處理哈希衝突
private void set(ThreadLocal<?> key, Object value) {
Entry[] tab = table;
int len = tab.length;
int i = key.threadLocalHashCode & (len - 1);
for (Entry e = tab[i]; e != null; e = tab[i = nextIndex(i, len)]) {
if (e.get() == key) { e.value = value; return; }
if (e.get() == null) { replaceStaleEntry(key, value, i); return; }
}
tab[i] = new Entry(key, value);
if (++size > threshold) rehash();
}
ThreadLocalIndex 直接索引,性能提升 2-3 倍,需配合 FastThreadLocalThreadTransmittableThreadLocal + TtlRunnable/TtlCallable 裝飾任務,自動傳遞上下文<dependency>
<groupId>com.alibaba</groupId>
<artifactId>transmittable-thread-local</artifactId>
<version>2.13.0</version>
</dependency>
TransmittableThreadLocal<UserPrincipal> userContext = new TransmittableThreadLocal<>();
ExecutorService executor = TtlExecutors.getTtlExecutorService(Executors.newFixedThreadPool(10));
userContext.set(currentUser);
executor.submit(() -> {
// 子線程自動繼承 userContext
System.out.println(UserContextHolder.getUser().getName());
});
ThreadLocal 是 Java 並發編程中實現「線程隔離」的核心工具,廣泛應用於框架基礎設施 (Spring、Hibernate、Dubbo)、業務上下文傳遞、非線程安全對象封裝。掌握其內存模型、洩漏防範、線程池傳遞方案,是編寫健壯高性能 Java 應用的必備技能。