1. 程式人生 > >在web專案中使用 ThreadLocal 要謹慎,使用不當容易造成記憶體溢位

在web專案中使用 ThreadLocal 要謹慎,使用不當容易造成記憶體溢位

這裡使用的servlet容器是 tomcat

如果在web專案中,使用 ThreadLocal 不當,會造成 OutOfMemoryError。

說明原因前
1:先講一下 ThreadLocal,Thead,ThreadLocalMap 三者之間的一個關係。(大家可以去看一下ThreadLocal的實現原始碼,可而參考我的另一篇文章點選檢視
ThreadLocalMap 是 ThreadLocal 的一個內部類,一看是Map,儲存資料的形式就是key value 形式的。
Thread類有一個成員變數 threadLocals,這個變數的資料型別是 ThreadLocal.ThreadLocalMap。threadLocals儲存資料的key是ThreadLocal本身

2:tomcat執行緒池
tomcat啟動的時候會建立一個執行緒池,配置如下

<Connector port="80" protocol="HTTP/1.1" maxThreads="600" minSpareThreads="100" maxSpareThreads="500" acceptCount="700"
connectionTimeout="20000" redirectPort="8443" />

maxThreads=”600” ///最大執行緒數
minSpareThreads=”100”///初始化時建立的執行緒數
maxSpareThreads=”500”///一旦建立的執行緒超過這個值,Tomcat就會關閉不再需要的socket執行緒。
acceptCount=”700”//指定當所有可以使用的處理請求的執行緒數都被使用時,可以放到處理佇列中的請求數,超過這個數的請求將不予處理

這裡說一下為什麼 如果在web專案中,使用 ThreadLocal 不當,會造成 OutOfMemoryError。
如果呼叫 ThreadLocal 的 set 方法 將一個物件放入Thread中的成員變數threadLocals 中,那麼這個物件是永遠不會被回收的,因為這個物件永遠都被Thread中的成員變數threadLocals引用這。

如果想讓垃圾收集器回收它,有兩種方法
1:將該執行緒從tomcat執行緒池中去除,當一個執行緒被回收的時候何況它的成員變數呢,但是tomcat啟動一般都會配置一個執行緒池進行優化,所有該方法不太現實。
2:呼叫 ThreadLocal 的 remove 方法 將物件從hread中的成員變數threadLocals 中刪除掉。

設想如果將一個大物件放入threadLocals 中,並且還沒有remove。那麼就可能會造成OutOfMemoryError,如果不會造成OutOfMemoryError那麼也很浪費java堆記憶體