java.util.concurrent包系列文章
JUC—ThreadLocal源碼解析(JDK13)
JUC—ThreadPoolExecutor線程池源碼解析(JDK13)
JUC—各種鎖(JDK13)
JUC—原子類Atomic*.java源碼解析(JDK13)
JUC—CAS源碼解析(JDK13)
JUC—ConcurrentHashMap源碼解析(JDK13)
JUC—CopyOnWriteArrayList源碼解析(JDK13)
JUC—併發隊列源碼解析(JDK13)
JUC—多線程下控制併發流程(JDK13)
JUC—AbstractQueuedSynchronizer解析(JDK13)
ThreadLocal -> 線程本地變量
- 強調同一個請求內(同一個線程內)不同方法間的共享
- 讓某個需要用到的對象在線程間隔離(每個線程都有自己獨有自己獨立的對象)
ThreadLocal的優點
- 達到線程安全
- 不需要加鎖
- 提高執行效率 高效利用內存
- 節省開銷 避免傳參的麻煩
Thread、ThreadLocal、ThreadLocalMap三者的關係
每個Thread對象中都持有一個ThreadLocalMap對象,可以看做是一個Map,key就是ThreadLocal,value就是放進去的對象。
所謂線程本地變量,其實就是把值存儲在當前線程的:
ThreadLocal的重要方法
public void set(T value) {
// 獲取當前線程
Thread t = Thread.currentThread();
// 獲取當前線程的ThreadLocalMap
ThreadLocalMap map = getMap(t);
if (map != null) {
// 把當前ThreadLocal作爲key
map.set(this, value);
} else {
// map爲空就初始化並設置值
createMap(t, value);
}
}
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
public T get() {
// 獲取當前線程
Thread t = Thread.currentThread();
// 獲取當前線程的ThreadLocalMap
ThreadLocalMap map = getMap(t);
if (map != null) {
// 把當前ThreadLocal作爲key,差U型你
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
// map爲空說明還未初始化
return setInitialValue();
}
private T setInitialValue() {
T value = initialValue();
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
map.set(this, value);
} else {
createMap(t, value);
}
if (this instanceof TerminatingThreadLocal) {
TerminatingThreadLocal.register((TerminatingThreadLocal<?>) this);
}
return value;
}
protected T initialValue() {
return null;
}
public void remove() {
// 獲取當前線程的ThreadLocalMap
ThreadLocalMap m = getMap(Thread.currentThread());
if (m != null) {
// m不爲空則移除元素
m.remove(this);
}
}
從get()、set()、remove()方法都可以看到,就是以當前線程爲變量爲key存儲線程本地變量。每一個線程都有自己的變量值。從而沒有線程安全問題。線程退出的時候必須調用remove()方法,防止溢出。
業務場景:在攔截器preHandle()方法中驗證用戶身份,驗證通過,則調用set()方法把當前用戶信息存入ThreadLocal。放行當前請求,當前請求進入業務系統,執行了各種業務處理之後,在攔截器的postHandle()和afterCompletion()方法中一定要調用remove()方法清楚當前線程本地變量。
ThreadLocal在Spring中的典型例子:RequestContextHolder、DateTimeContextHolder
public abstract class RequestContextHolder {
private static final boolean jsfPresent =
ClassUtils.isPresent("javax.faces.context.FacesContext", RequestContextHolder.class.getClassLoader());
private static final ThreadLocal<RequestAttributes> requestAttributesHolder =
new NamedThreadLocal<>("Request attributes");
private static final ThreadLocal<RequestAttributes> inheritableRequestAttributesHolder =
new NamedInheritableThreadLocal<>("Request context");
、、、省略、、、
@Nullable
public static RequestAttributes getRequestAttributes() {
RequestAttributes attributes = requestAttributesHolder.get();
if (attributes == null) {
attributes = inheritableRequestAttributesHolder.get();
}
return attributes;
}
}
- 我的公衆號:Coding摳腚
- 一個被電焊耽誤的Java程序員。偶爾發發自己最近學到的乾貨。學習路線,經驗,技術分享。技術問題交流探討。