ThreadLocal的介紹與運用

ThreadLocal全面解析學習目標

  • 了解ThreadLocal的介紹
  • 掌握ThreadLocal的運用場景
  • 了解ThreadLocal的內部結構
  • 了解ThreadLocal的核心方法源碼
  • 了解ThreadLocalMap的源碼
1. ThreadLocal介紹1.1 官方介紹/** * This class provides thread-local variables.These variables differ from * their normal counterparts in that each thread that accesses one (via its * {@code get} or {@code set} method) has its own, independently initialized * copy of the variable.{@code ThreadLocal} instances are typically private * static fields in classes that wish to associate state with a thread (e.g., * a user ID or Transaction ID). * * <p>For example, the class below generates unique identifiers local to each * thread. * A thread's id is assigned the first time it invokes {@code ThreadId.get()} * and remains unchanged on subsequent calls. * <pre> * import java.util.concurrent.atomic.AtomicInteger; * * public class ThreadId { *// Atomic integer containing the next thread ID to be assigned *private static final AtomicInteger nextId = new AtomicInteger(0); * *// Thread local variable containing each thread's ID *private static final ThreadLocal&lt;Integer&gt; threadId = *new ThreadLocal&lt;Integer&gt;() { *@Override protected Integer initialValue() { *return nextId.getAndIncrement(); *} *}; * *// Returns the current thread's unique ID, assigning it if necessary *public static int get() { *return threadId.get(); *} * } * </pre> * <p>Each thread holds an implicit reference to its copy of a thread-local * variable as long as the thread is alive and the {@code ThreadLocal} * instance is accessible; after a thread goes away, all of its copies of * thread-local instances are subject to garbage collection (unless other * references to these copies exist). * * @authorJosh Bloch and Doug Lea * @since1.2 */public class ThreadLocal<T> {...? 從Java官方文檔中的描述:ThreadLocal類用來提供線程內部的局部變量 。這種變量在多線程環境下訪問(通過get和set方法訪問)時能保證各個線程的變量相對獨立于其他線程內的變量 。ThreadLocal實例通常來說都是private static類型的,用于關聯線程和線程上下文 。
我們可以得知 ThreadLocal 的作用是:提供線程內的局部變量,不同的線程之間不會相互干擾,這種變量在線程的生命周期內起作用 , 減少同一個線程內多個函數或組件之間一些公共變量傳遞的復雜度 。總結:1. 線程并發: 在多線程并發的場景下2. 傳遞數據: 我們可以通過ThreadLocal在同一線程 , 不同組件中傳遞公共變量3. 線程隔離: 每個線程的變量都是獨立的 , 不會相互影響1.2 基本使用1.2.1 常用方法? 在使用之前,我們先來認識幾個ThreadLocal的常用方法
方法聲明描述ThreadLocal()創建ThreadLocal對象public void set( T value)設置當前線程綁定的局部變量public T get()獲取當前線程綁定的局部變量public void remove()移除當前線程綁定的局部變量1.2.2 使用案例我們來看下面這個案例public class MyDemo {private String content;private String getContent() {return content;}private void setContent(String content) {this.content = content;}public static void main(String[] args) {MyDemo demo = new MyDemo();for (int i = 0; i < 5; i++) {Thread thread = new Thread(new Runnable() {@Overridepublic void run() {demo.setContent(Thread.currentThread().getName() + "的數據");System.out.println("-----------------------");System.out.println(Thread.currentThread().getName() + "--->" + demo.getContent());}});thread.setName("線程" + i);thread.start();}}}打印結果:
ThreadLocal的介紹與運用

文章插圖
? 從結果可以看出多個線程在訪問同一個變量的時候出現的異常,線程間的數據沒有隔離 。下面我們來看下采用 ThreadLocal 的方式來解決這個問題的例子 。
public class MyDemo {private static ThreadLocal<String> tl = new ThreadLocal<>();private String content;private String getContent() {return tl.get();}private void setContent(String content) {tl.set(content);}public static void main(String[] args) {MyDemo demo = new MyDemo();for (int i = 0; i < 5; i++) {Thread thread = new Thread(new Runnable() {@Overridepublic void run() {demo.setContent(Thread.currentThread().getName() + "的數據");System.out.println("-----------------------");System.out.println(Thread.currentThread().getName() + "--->" + demo.getContent());}});thread.setName("線程" + i);thread.start();}}}打印結果:
?
ThreadLocal的介紹與運用

文章插圖
從結果來看,這樣很好的解決了多線程之間數據隔離的問題,十分方便 。
1.3 ThreadLocal類與synchronized關鍵字1.3.1 synchronized同步方式? 這里可能有的朋友會覺得在上述例子中我們完全可以通過加鎖來實現這個功能 。我們首先來看一下用synchronized代碼塊實現的效果:

推薦閱讀