ThreadLocal怎么实现线程隔离的?可见性问题?为什么要重新定义一个threadLocalHashCode?为什么有内存泄露?弱引用又是什么?
1. ThreadLocal實現線程隔離的使用場景
線程1的if代碼塊要執行的話,那么flag.get()的值必須是false;同理線程2的if代碼塊要執行的話,flag.get()的值必須是true。也就是說線程1要得到線程2對flag變量操作的值,線程2要得到線程1操作的值。最終沒有任何結果輸出,說明兩個線程沒有得到對方修改的內容。
有些小伙伴就說了,各自線程得不到對方操作的內容不是很正常嗎?這就是可見性問題啊。確實,由于共享數據存在可見性問題,線程間的數據不能得到很好的同步,也會出現上述場景。那我設計了如下代碼,證明了:即使有可見性問題,仍然存在一個線程讀取到其它線程操作內容的情況。
因此,我們可以確定ThreadLocal的數據是實現線程隔離的,而且它的目的就是讓各個線程之間不可見。
?
2. ThreadLocal怎么實現線程隔離
2.1 首先,ThreadLocal對象只給我們提供了三個方法,set、get和remove,那接下來對這三個方法分析一下。
2.2 set方法,賦值是將數據保存到各個線程的ThreadLocalMap中,從而實現線程隔離。
2.3 ThreadLocalMap的set方法實現——ThreadLocal對象為什么要重新定義threadLocalHashCode
2.4 get方法比較簡單
2.5 remove()方法——防止內存泄露
網上都說ThreadLocal存在內存泄露,這到底是怎么回事呢?對于一個ThreadLocal來說,它是作為key放在ThreadLocalMap中的,當這個ThreadLocal對象結束了生命,那么它應該被回收。但由于ThreadLocalMap是線程屬性,生命周期和線程一樣長;線程還未結束時ThreadLocalMap自然有ThreadLocal對象的引用,ThreadLocal也就無法被回收了。于是,開發者將ThreadLocal和ThreadLocalMap之間的引用改為弱引用,Entry不再是一般的鍵值對,而只有一個value屬性,key通過一種弱引用形式表現。這樣當ThreadLocal沒有了強引用,只有ThreadLocalMap的弱引用,ThreadLocal會被回收。
但是這邊又出現了一個問題,雖然Entry的key使用了弱引用,ThreadLocal對象可以被回收。但是Entry的value再也無法通過key訪問了,無法回收,value還是存在內存泄露。所以一般在使用ThreadLocal結束后,要調用remove方法,去除key的引用,同時將value值置為null。
總結
以上是生活随笔為你收集整理的ThreadLocal怎么实现线程隔离的?可见性问题?为什么要重新定义一个threadLocalHashCode?为什么有内存泄露?弱引用又是什么?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java源码编译为字节码的流程
- 下一篇: Mybatis工作流程,附带mybati