您好,登錄后才能下訂單哦!
這篇文章主要講解了“不規范使用ThreadLocal導致bug如何解決”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“不規范使用ThreadLocal導致bug如何解決”吧!
ThreadLocal一般用于線程間的數據隔離,通過將數據緩存在ThreadLocal中,可以極大的提升性能。但是,如果錯誤的使用Threadlocal,可能會引起不可預期的bug,以及造成內存泄露。
有時我們會在一個接口中緩存某些數據到ThreadLocal中,但是我們要意識到,處理請求的這些線程是由tomcat提供的,而tomcat提供的線程都是配置在一個線程池中的。
也就是說,線程是可能被重用的,如果線程一旦被重用,而ThreadLocal的數據沒有及時重置,就會導致數據被混亂使用。
以下方的接口為例,先獲取當前線程中保存的數據信息,將參數中的name保存到ThreadLocal中以后,再獲取一次。
@GetMapping(value = "/threadLocal") public ResponseEntity<Object> threadLocal(String name) { String before = Thread.currentThread().getName() + ":" + threadLocal.get(); //先獲取值,理論上應該是null System.out.println("before:" + before); threadLocal.set(name); String after = Thread.currentThread().getName() + ":" + threadLocal.get(); //設置完參數值再獲取一次 System.out.println("after:" + after); return ResponseEntity.ok().build(); }
為了盡快復現線程重用導致的問題,我們將servlet.tomcat.threads.max設置為1,這樣每次請求使用的都是同一個線程。
第一次請求接口,數據看起來很正常:
但是第二次請求接口時,可以看到線程仍然是http-nio-8080-exec-1,但是before卻打印出了第一次請求的參數test。
這就是因為沒有及時重置ThreadLocal導致的數據錯誤。
修正的辦法就是處理完接口之后要及時清理ThreadLocal。
@GetMapping(value = "/threadLocal") public ResponseEntity<Object> threadLocal(String name) { try { String before = Thread.currentThread().getName() + ":" + threadLocal.get(); //先獲取值,理論上應該是null System.out.println("before:" + before); threadLocal.set(name); String after = Thread.currentThread().getName() + ":" + threadLocal.get(); //設置完參數值再獲取一次 System.out.println("after:" + after); } finally { //清理數據 threadLocal.remove(); } return ResponseEntity.ok().build(); }
可能也有的朋友會說,每次都要使用try finally處理線程數據,未免也太麻煩了。其實,我們可以使用攔截器或者過濾器自動幫我們完成數據的初始化以及清理工作。
感謝各位的閱讀,以上就是“不規范使用ThreadLocal導致bug如何解決”的內容了,經過本文的學習后,相信大家對不規范使用ThreadLocal導致bug如何解決這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。