在使用spring boot的時候,發現這麼樣一個很有意思的功能:
RequestContextHolder.getRequestAttributes()).getRequest()
可以通過這麼樣的一個類來獲取當前的Request對象,第一反應就是spring boot替我們完成了request對象與當前線程的綁定。
那這內部,又是如何實現的?
這個RequestContenxtHolder裏面有一個ThreadLocal對象,這個對象,就是實現數據與線程綁定的核心對象。
那麼ThreadLocal又是什麼?
從源碼的註釋大概可以瞭解到,這個類可以用來實現線程本地變量,我們來做個試驗:
public class Main{
private ThreadLocal<String> threadLocal = new ThreadLocal<>();
public void set(String str){
threadLocal.set(str);
}
public String get(){
return threadLocal.get();
}
public static void main(String[] args) throws InterruptedException {
Main main = new Main();
main.set("hello");
Thread thread = new Thread(()->main.set("world"));
thread.start();
thread.join();
System.out.println(main.get());
}
}
當運行這個程序的時候,會輸出什麼?
結果是hello,由於thread線程肯定是會在set("hello")之後,join()之前運行完畢的,所以我們可以從這個小例子當中初步瞭解ThreadLocal的用法。
那麼我們知道,在JAVA內存模型當中,分爲公共內存和線程私有內存,或者也叫工作內存。
線程私有內存是在棧上,那麼我們能不能據此判斷,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);
}
}
get方法:
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}
getMap方法:
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
從這三個方法來看,線程對象內部有一個ThreadLocal.ThreadLocalMap對象:
正是通過這個map,才實現了ThreadLocal與數據的綁定