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