ThreadLocal存List遇到的坑


之前為了方便一個Service下共用List,將List作為類成員變量,當然有點線程安全意識的兄弟們都知道不能就這么直接加在上面。

1 public class PermService {
3     private List<String> list;
5     ....    
6 }

當然用鎖(synchronized)又還不至於,於是這里用了線程本地變量ThreadLocal,如下:

 1 public class PermService {
 2 
 3     private static final ThreadLocal<List<String>> STR_LIST = new ThreadLocal<List<String>>() {
 4         @Override
 5         protected List<String> initialValue() {
 6             return new ArrayList<String>();
 7         }
 8     };
 9     ....  
10 }

然后我每次請求進來之后都是類似於這么處理的

1 public void storePermsByRole(String roleId) {
2   List<String> permIds = rolePermMapper.selectPermByRole(roleId);
3   STR_LIST.get().addAll(permIds);
4 }

后面用postman測的時候問題來了:原本和這個roleId沒有關系的permId在返回體里面出現了,查了下庫里面也沒有這兩個關系的記錄,debug斷點打到上面的第3行permIds里面也沒有那一條數據,那么這多出來的一條是哪來的呢?

 

苦思冥想意識到可能和線程池有關系(這里說的線程池不是你配的全局線程池,也不是手動用Executors生成的線程池),所有線程池一般有個核心線程數,這些線程是不會在一個請求request結束后就銷毀的,而線程本地變量又是依附於線程的(具體可以理解下ThreadLocalMap),所以一個線程上一個請求將數據庫中查出來的list加到線程本地變量后,下一個請求進來原來的list還在里面,從而導致了上面的問題。

這里解決方法是在service中加一段清空ThreadLocal的邏輯,在請求結束之前調一下即可。

1 public void clearThreadLocal() {
2   STR_LIST.remove();
3 }

 

ThreadLocal用的守則:

1、請求開始時set

2、請求結束前remove

3、加static關鍵字

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM