首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 多線程基礎總結(四):ThreadLocal 線程本地變量詳解

     編輯:Java 相關知識

ThreadLocal 名稱易誤以為是「Thread 的親戚」,實則意為**線程本地變量**——每個線程擁有獨立副本,將共享變量轉化為線程隔離的私有變量,從根本上消除併發衝突。

核心設計原理

  • 內部維護一個 **線程安全的 Map**(ThreadLocalMap),鍵為 ThreadLocal 實例,值為線程副本。
  • get() 時若無副本,調用 initialValue() 初始化並綁定當前線程。
  • 所有操作僅針對當前線程的副本,**零同步、零等待**。

適用場景:有狀態但無需共享

典型例子:DAO 持有 Connection。多線程共用 DAO 實例時,Connection 的連接/關閉狀態極易衝突。用 ThreadLocal 給每個線程分配獨立 Connection,線程間互不干擾,性能大增。

空間換時間:與 synchronized 博弈

  • ThreadLocal:多佔內存(每線程一份副本),**絕不等待**。
  • synchronized:省內存,**接受等待**。
  • 本質是**時空權衡**,視業務場景選擇。

三個版本演進示例

// 版本 1:無同步,共享 num → 結果混亂
class OperationSample {
    private int num;
    public void printAndIncrementNum() {
        for (int i=0; i<2; i++) {
            System.out.println(Thread.currentThread().getName() + "[id=" + num + "]");
            num += 10;
        }
    }
}

// 版本 2:ThreadLocal 隔離,每線程初始 0 → 每線程輸出 0, 10
class OperationSample2 {
    private static ThreadLocal<Integer> threadArg = new ThreadLocal<Integer>() {
        protected Integer initialValue() { return 0; }
    };
    public void printAndIncrementNum() {
        for (int i=0; i<2; i++) {
            int num = threadArg.get();
            threadArg.set(num + 10);
            System.out.println(Thread.currentThread().getName() + "[id=" + num + "]");
        }
    }
}

// 版本 3:配合 AtomicInteger 分配唯一初始值 → 線程首次輸出 0~4,第二次 +10
class OperationSample3 {
    private static final AtomicInteger uniqueId = new AtomicInteger(0);
    private static ThreadLocal<Integer> threadArg = new ThreadLocal<Integer>() {
        protected Integer initialValue() { return uniqueId.getAndIncrement(); }
    };
    // printAndIncrementNum 同版本 2
}

實戰應用與注意

  • Spring 大量使用 ThreadLocal 管理事務、Session 等非線程安全狀態。
  • JDK 早期版本性能較差,現代 JDK 已優化優於 synchronized。
  • 記得在線程結束前 remove() 避免內存洩漏(線程池場景尤其重要)。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved