在Multithreading的專案中,使用ThreadLocal儲存各自的變數
主題: |
在Multithreading的專案中,使用ThreadLocal儲存各自的變數 |
文章簡介: |
介紹在multithreading的情況下,如何使用全域變數(global variable),彼此的內容又不會互相影響,並且注意到,透過這樣的解決方案,是否可能導致其他問題產生! |
作者: |
陳膺傑 |
版本/產出日期: |
V1.0/2016.12.08 |
1. 前言
• 在開發Web Services時,若可能遇到多人同時呼叫,透過Multi Thread進行處理時,在使用全域變數(global variable)上,就得特別小心可能存在值被覆蓋的問題。
2. 目的
• 為解決Multi Thread下使用全域變數(global variable),內容會互相覆蓋的問題,可透過ThreadLocal來存放專屬於當前Thread的全域變數(global variable)。
• 當ThreadLocal遇上Thread Pool時,可能產生嚴重的問題!必須先了解並預防!
3. 使用ThreadLocal
• 從JDK5.0開始,ThreadLocal已支援泛型,透過set存入value,透過get取得value。
4. ThreadLocal範例演練
4.1、 建立一個RESTful的Web Service,當接到的內容不為空即存入ThreadLocal,接著呼叫另一個method來取得ThreadLocal的內容,回傳內容。
4.2、 同時呼叫此Web Service時,彼此結果並不會互相影響。
圖一:輸入「Jay Chen」,成功取得「Jay Chen」
圖二:輸入「Adam」,成功取得「Adam」。
5. 當ThreadLocal遇上Thread Pool
5.1、 當上述的範例,不輸入內容再次同時呼叫
圖一:Thread-1仍然取得「Jay Chen」
圖二:Thread-2仍然取得「Adam」
5.2、 會發生此錯亂,全是因為Thread Pool的影響,Thread受到Thread Pool的管理,在處理流程結束後,回到Thread Pool等著處理下一筆request,為了效能,通常這些Threads並不會一直重新產生,而是重複利用,所以當我們使用ThreadLocal存放變數時,若是沒有任何初始或清除的動作,將會被下一個使用者取到上一個使用者的內容。
6. 解決辦法
6.1、 新增清除的method
6.2、 在結束流程後,清除ThreadLocal,原本的Web Service調整如下
6.3、 再次進行測試
圖一:輸入「BoB」,在Thread-2成功取得BoB
圖二:不輸入內容,在Thread-2取不到內容
7. 結論
• 現行大多數的Server都會透過Thread Pool來管理Threads,因此在使用ThreadLocal上,需要特別注意,在流程處理結束後,必須清除所有存放的ThreadLocal,以確保不會造成這種資料錯亂的情況,更嚴重的情況還可能導致Memory leak!
8. 參考來源
• Java ThreadLocal-http://tutorials.jenkov.com/java-concurrency/threadlocal.html
• ThreadLocal Variables and Thread Pools – It Can Go Wrong-https://techblog.bozho.net/threadlocal-variables-and-thread-pools-it-can-go-wrong/
• A Painless Introduction to Java’s ThreadLocal Storage-https://www.appneta.com/blog/introduction-to-javas-threadlocal-storage/
• Ensure ThreadLocal variables are reinitialized when using thread pools-https://www.securecoding.cert.org/confluence/display/java/TPS04-J.+Ensure+ThreadLocal+variables+are+reinitialized+when+using+thread+pools