基本 ThreadLocal 用法

Java ThreadLocal 用於建立執行緒區域性變數。眾所周知,Object 的執行緒共享它的變數,因此該變數不是執行緒安全的。我們可以使用同步來保證執行緒安全,但是如果我們想避免同步,ThreadLocal 允許我們建立執行緒本地的變數,即只有那個執行緒可以讀取或寫入那些變數,所以其他執行緒執行同一段程式碼將無法訪問彼此的 ThreadLocal 變數。

這可以用來使用 ThreadLocal 變數。在你有一個執行緒池的情況下,例如在 Web 服務中。例如,每次為每個請求建立一個 SimpleDateFormat 物件都非常耗時,並且由於 SimpleDateFormat 不是執行緒安全的,因此無法建立靜態物件,因此我們可以建立一個 ThreadLocal,以便我們可以執行執行緒安全操作,而無需每次建立 SimpleDateFormat 的開銷時間。

下面的程式碼顯示瞭如何使用它:

每個執行緒都有自己的 ThreadLocal 變數,他們可以使用 get()set() 方法來獲取預設值或將其值更改為 Thread 的本地值。

ThreadLocal 例項通常是希望將狀態與執行緒相關聯的類中的私有靜態欄位。

這是一個小例子,展示了在 java 程式中使用 ThreadLocal 並證明每個執行緒都有自己的 ThreadLocal 變數副本。

package com.examples.threads;

import java.text.SimpleDateFormat;
import java.util.Random;

public class ThreadLocalExample implements Runnable{

    // SimpleDateFormat is not thread-safe, so give one to each thread
 // SimpleDateFormat is not thread-safe, so give one to each thread
    private static final ThreadLocal<SimpleDateFormat> formatter = new ThreadLocal<SimpleDateFormat>(){
        @Override
        protected SimpleDateFormat initialValue()
        {
            return new SimpleDateFormat("yyyyMMdd HHmm");
        }
    };
    
    public static void main(String[] args) throws InterruptedException {
        ThreadLocalExample obj = new ThreadLocalExample();
        for(int i=0 ; i<10; i++){
            Thread t = new Thread(obj, ""+i);
            Thread.sleep(new Random().nextInt(1000));
            t.start();
        }
    }

    @Override
    public void run() {
        System.out.println("Thread Name= "+Thread.currentThread().getName()+" default Formatter = "+formatter.get().toPattern());
        try {
            Thread.sleep(new Random().nextInt(1000));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        
        formatter.set(new SimpleDateFormat());
        
        System.out.println("Thread Name= "+Thread.currentThread().getName()+" formatter = "+formatter.get().toPattern());
    }

}

輸出:

Thread Name= 0 default Formatter = yyyyMMdd HHmm

Thread Name= 1 default Formatter = yyyyMMdd HHmm

Thread Name= 0 formatter = M/d/yy h:mm a

Thread Name= 2 default Formatter = yyyyMMdd HHmm

Thread Name= 1 formatter = M/d/yy h:mm a

Thread Name= 3 default Formatter = yyyyMMdd HHmm

Thread Name= 4 default Formatter = yyyyMMdd HHmm

Thread Name= 4 formatter = M/d/yy h:mm a

Thread Name= 5 default Formatter = yyyyMMdd HHmm

Thread Name= 2 formatter = M/d/yy h:mm a

Thread Name= 3 formatter = M/d/yy h:mm a

Thread Name= 6 default Formatter = yyyyMMdd HHmm

Thread Name= 5 formatter = M/d/yy h:mm a

Thread Name= 6 formatter = M/d/yy h:mm a

Thread Name= 7 default Formatter = yyyyMMdd HHmm

Thread Name= 8 default Formatter = yyyyMMdd HHmm

Thread Name= 8 formatter = M/d/yy h:mm a

Thread Name= 7 formatter = M/d/yy h:mm a

Thread Name= 9 default Formatter = yyyyMMdd HHmm

Thread Name= 9 formatter = M/d/yy h:mm a

正如我們從輸出中看到的那樣,Thread-0 已經改變了 formatter 的值,但仍然是 thread-2 預設格式化程式與初始化值相同。