廖雪峯Java11多線程編程-4線程工具類-1ThreadLocal

多線程是Java實現多任務的基礎:java

  • Thread
  • ExecutorService
  • ScheduledThreadPool
  • Fork/Join

Thread對象表明一個線程:調用Tread.currentThread()獲取當前線程。
多任務程序一般須要針對每一個任務啓動一個新的線程,來處理這個用戶的請求,也能夠從線程池取出一個空閒的線程來處理。

如何在一個線程內傳遞狀態:
例如咱們在一個線程處理過程當中,常常須要調用不一樣的類來處理不一樣的功能,咱們如何在這些方法中可以方便的獲取到當前的用戶?

JDK提供了ThreadLocal在一個線程中傳遞同一個對象多線程

static ThreadLocal<String> threadLocalUser = new ThreadLocal<>();
    threadLocalUser.set("Bob"); //給當前線程綁定一個指定的值
    ...
    String current = threadLocalUser.get(); //調用get()方法能夠在當前線程隨時獲取到已綁定的這個值
    String current = threadLocalUser.get();
    String current = threadLocalUser.get();
    ...
    threadLocalUser.remove(); //把綁定的值從當前線程中解除

ThreadLocal典型的使用方式:

ThreadLocal必定要在finally中清除。當前線程執行完相關代碼之後,頗有可能從新放入線程池中,若是ThreadLocal沒有被清除,這個線程在執行其餘代碼的時候,就會把上一次的狀態帶進去。this

try{
        UserContext.set(user);
    ...
    }finally{
        UserContext.remove();
    }
class User{ //表示當前的一個用戶
    String name;
    int level;
    public User(String name, int level){
        this.name = name;
        this.level = level;
    }
}
class UserContext implements AutoCloseable{
    static final ThreadLocal<User> context = new ThreadLocal<>(); //全局惟一靜態變量
    public static User getCurrentUser(){    //獲取當前線程的ThreadLocal User
        return context.get();
    }
    public UserContext(User user){ //初始化ThreadLocal的User
        context.set(user);
    }
    public void close(){ //移除ThreadLocal關聯的User
        context.remove();
    }
}
class ProcessThread extends Thread{
    User user;
    ProcessThread(User user){ //傳入User對象
        this.user = user;
    }
    public void run(){
        try(UserContext ctx = new UserContext(user)){
            new Greeting().hello();
            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) throws Exception{
        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結構
相關文章
相關標籤/搜索