日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

log(二)——MDC实现之ThreadLocal

發布時間:2024/3/13 编程问答 46 豆豆
生活随笔 收集整理的這篇文章主要介紹了 log(二)——MDC实现之ThreadLocal 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

?因為MDC底層是用ThreadLocal實現的,所以這里補充一些和ThreadLocal相關的知識點。

1.ThreadLocal的三個層次

關于ThreadLocal有三個層次,可以按照這三個層次去理解就不會亂。

三個層次
?* 第一層是Thread空間,通過Thread.currentThread()獲得。
?* 第二層是Thread中的兩個ThreadLocalMap,threadLocals和inheritableThreadLocals,訪問thread對應的兩個ThreadLocalMap成員變量獲得。
?* 第三層是每個ThreadLocalMap中key——ThreadLocal和value——ThreadLocal的set方法set的值,在get方法中用ThreadLocal的this作為ThreadLocalMap的key獲取value。
?* 無論什么操作都要按照這三個層次依次進行才不會亂

2.ThreadLocalMap

保存了當前Thread中存放的ThreadLocal和ThreadLocal對應的值的鍵值對。

當前線程的所有ThreadLocal變量組成了這個map的keyset,對應的值組成了這個map的valueset。

3.ThreadLocal的操作

第一步都是先用Thread.currentThread()獲得當前線程,然后getMap獲取線程中的ThreadLocalMap。

像getMap這些操作方法都是包可見性的,包外部無法操作。以ThreadLocal的get方法舉例,

/*** Returns the value in the current thread's copy of this* thread-local variable. If the variable has no value for the* current thread, it is first initialized to the value returned* by an invocation of the {@link #initialValue} method.** @return the current thread's value of this thread-local*/public T get() {Thread t = Thread.currentThread();ThreadLocalMap map = getMap(t);if (map != null) {ThreadLocalMap.Entry e = map.getEntry(this);if (e != null)return (T)e.value;}return setInitialValue();}

4.InheritableThreadLocal

Thread類中有兩個ThreadLocalMap,一個是threadLocals,一個是inheritableThreadLocals。

threadLocals保存的是當前線程中的ThreadLocal變量們,inheritableThreadLocals保存的是當前線程父線程中的變量們。

InheritableThreadLocal類覆寫了getMap和createMap這兩個方法,

/*** Get the map associated with a ThreadLocal.** @param t the current thread*/ThreadLocalMap getMap(Thread t) {return t.inheritableThreadLocals;} /*** Create the map associated with a ThreadLocal.** @param t the current thread* @param firstValue value for the initial entry of the table.* @param map the map to store.*/void createMap(Thread t, T firstValue) {t.inheritableThreadLocals = new ThreadLocalMap(this, firstValue);}

可以看出在初始化或者getMap的時候,獲取到的都是inheritableThreadLocals引用,操作的也是inheritableThreadLocals這個ThreadLocalMap。

5.threadLocals和inheritableThreadLocals的初始化

/*** Initializes a Thread.** @param g the Thread group* @param target the object whose run() method gets called* @param name the name of the new Thread* @param stackSize the desired stack size for the new thread, or* zero to indicate that this parameter is to be ignored.*/private void init(ThreadGroup g, Runnable target, String name,long stackSize) {...Thread parent = currentThread();...if (parent.inheritableThreadLocals != null)this.inheritableThreadLocals =ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);...}

在new一個Thread的時候會調用Thread的init方法,該方法中如果parent線程的inheritableThreadLocals不是null的話,就會用createInheritedMap方法,用parent的inheritableThreadLocals中的元素構造一個新的ThreadLocalMap。

注意:該操作只在線程初始化的時候進行,所以在該線程初始化之后,parent線程對parent線程自己的inheritableThreadLocals變量的操作不會影響到當前線程的inheritableThreadLocals了,因為已經不是同一個map了。

MDC就是利用這個InheritableThreadLocal把父線程的context帶到子線程中,把上下文傳遞到子線程中通過日志輸出,把一次完整的請求串聯起來。

6.parent線程

Thread parent = currentThread();

在Thread的init方法中,是通過獲得當前線程作為parent線程,也就是說,在哪個線程中new的這個Thread并start的,執行該操作的線程就是new的新Thread的parent線程。

但是init方法只在線程初始化的時候執行一次,所以如果用的線程池來使線程重用的話,就不會再調用這個init方法了,這會帶來一些問題,后面會具體說。
?

總結

以上是生活随笔為你收集整理的log(二)——MDC实现之ThreadLocal的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。