摘要:另載于是個(gè)很爽的東西,線程安全,能當(dāng)全局變量來(lái)用別。第一家公司,使用框架老技術(shù),現(xiàn)代人可以理解為類似,對(duì)每個(gè)請(qǐng)求都套上,進(jìn)入時(shí)把寫入,返回或拋?zhàn)⒁鈺r(shí)清理。第二家公司,某次引入一個(gè)設(shè)計(jì),也用了來(lái)傳遞上下文信息,有的地方?jīng)]能清掉。
另載于 http://www.qingjingjie.com/blogs/12
ThreadLocal是個(gè)很爽的東西,線程安全,能當(dāng)全局變量來(lái)用(別!)。
上一篇末尾提到ThreadLocal的妙用,這東西確實(shí)在框架實(shí)現(xiàn)中很常用。不過(guò)一定要小心啊。
先告訴大家一個(gè)安全秘訣:try-finally大法,百戰(zhàn)百勝?。ㄒ欢ㄒ趂inally里清空ThreadLocal)
我職業(yè)生涯遇到最棘手的并發(fā)bug都是ThreadLocal造成的,稱之為ThreadLocal污染問(wèn)題。
第一家公司,使用Seam框架(老技術(shù),現(xiàn)代人可以理解為類似Spring MVC),Seam對(duì)每個(gè)請(qǐng)求都套上Filter,進(jìn)入時(shí)把context寫入ThreadLocal,返回或拋Exception(注意)時(shí)清理ThreadLocal。而我們用了很多的庫(kù),有的庫(kù)會(huì)拋Error,用catch(Exception e)是抓不住的。這就導(dǎo)致有時(shí)ThreadLocal沒(méi)有被清掉,而服務(wù)器用的是線程池,線程會(huì)復(fù)用啊,那下次請(qǐng)求是不是可能讀到錯(cuò)誤的context呢?聽起來(lái)好嚴(yán)重?。?/p>
倒也不會(huì),Seam遇到下一個(gè)請(qǐng)求又會(huì)把新的context寫入ThreadLocal,覆蓋舊值,就算舊值沒(méi)釋放也不要緊。然而!我們的系統(tǒng)有的模塊沒(méi)有用Seam,而我們有個(gè)內(nèi)部框架,為了兼容性,會(huì)檢測(cè)當(dāng)前線程是否存在Seam context,如果存在,就從context取對(duì)象,如果不存在,就另尋蹊徑。有的Filter掛在Seam Filter前面,如果那個(gè)Filter調(diào)到內(nèi)部框架,就會(huì)先檢測(cè)當(dāng)前線程是否存在Seam context,就讀到上次的context了。
這樣就會(huì)出現(xiàn)一些詭異的運(yùn)行結(jié)果,理論上污染會(huì)逐漸擴(kuò)大,直到服務(wù)器重啟才恢復(fù)。更詭異的是如果被污染的線程下次遇到了Seam Filter,覆蓋舊值,就又恢復(fù)正常了,讓人抓不到。
最后當(dāng)然是診斷并解決了這個(gè)問(wèn)題啦(只能靠推理o(╯□╰)o)。我順便看了Spring MVC的代碼,是用了try-finally大法的,經(jīng)得起考驗(yàn)。
第二家公司,某次引入一個(gè)設(shè)計(jì),也用了ThreadLocal來(lái)傳遞上下文信息,有的地方?jīng)]能清掉ThreadLocal。于是詭異bug冒出來(lái),百分之一概率出現(xiàn)各種稀奇古怪的運(yùn)行結(jié)果,看不出規(guī)律,就是怪。所以大家還是能看到一點(diǎn)規(guī)律的——那就是沒(méi)有規(guī)律!
現(xiàn)在大家應(yīng)該明白要怎么對(duì)待ThreadLocal了吧。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/64533.html
摘要:而應(yīng)用場(chǎng)景更多是想共享一個(gè)變量,但是該變量又不是線程安全的,那么可以用維護(hù)一個(gè)線程一個(gè)實(shí)例。因?yàn)閯?chuàng)建這個(gè)對(duì)象本身很費(fèi)時(shí)的,而且我們也知道本身不是線程安全的,也不能緩存一個(gè)共享的實(shí)例,為此我們想到使用來(lái)給每個(gè)線程緩存一個(gè)實(shí)例,提高性能。 很多人都知道java中有ThreadLocal這個(gè)類,但是知道ThreadLocal這個(gè)類具體有什么作用,然后適用什么樣的業(yè)務(wù)場(chǎng)景還是很少的。今天我就嘗...
摘要:如何在線程池中提交線程內(nèi)存模型相關(guān)問(wèn)題什么是的內(nèi)存模型,中各個(gè)線程是怎么彼此看到對(duì)方的變量的請(qǐng)談?wù)動(dòng)惺裁刺攸c(diǎn),為什么它能保證變量對(duì)所有線程的可見性既然能夠保證線程間的變量可見性,是不是就意味著基于變量的運(yùn)算就是并發(fā)安全的請(qǐng)對(duì)比下對(duì)比的異同。 并發(fā)編程高級(jí)面試面試題 showImg(https://upload-images.jianshu.io/upload_images/133416...
摘要:缺點(diǎn)每次調(diào)用都有線程開銷延遲初始化單例默認(rèn)構(gòu)造方法為,避免用戶用構(gòu)造出新對(duì)象獲取單例的靜態(tài)工廠同步方法延遲初始化單例使用同步方法保證多線程操作只實(shí)例化一個(gè)實(shí)力單例模式。 主要分為兩種: 直接初始化 延遲初始化 直接初始化 直接初始化final靜態(tài)成員 線程安全:JVM保證final靜態(tài)成員只會(huì)被初始化一次 公有靜態(tài)成員是個(gè)final域,直接引用成員獲取單例 /** * 公有靜態(tài)成...
摘要:方法,刪除當(dāng)前線程綁定的這個(gè)副本數(shù)字,這個(gè)值是的值,普通的是使用鏈表來(lái)處理沖突的,但是是使用線性探測(cè)法來(lái)處理沖突的,就是每次增加的步長(zhǎng),根據(jù)參考資料所說(shuō),選擇這個(gè)數(shù)字是為了讓沖突概率最小。 showImg(https://segmentfault.com/img/remote/1460000019828633); 老套路,先列舉下關(guān)于ThreadLocal常見的疑問(wèn),希望可以通過(guò)這篇學(xué)...
摘要:在方法中取出開始時(shí)間,并計(jì)算耗時(shí)。是一個(gè)數(shù)組主要用來(lái)保存具體的數(shù)據(jù),是的大小,而這表示當(dāng)中元素?cái)?shù)量超過(guò)該值時(shí),就會(huì)擴(kuò)容。如果這個(gè)剛好就是當(dāng)前對(duì)象,則直接修改該位置上對(duì)象的。 想要獲取更多文章可以訪問(wèn)我的博客?-?代碼無(wú)止境。 什么是ThreadLocal ThreadLocal在《Java核心技術(shù) 卷一》中被稱作線程局部變量(PS:關(guān)注公眾號(hào)itweknow,回復(fù)Java核心技術(shù)獲取該...
閱讀 1755·2019-08-30 15:54
閱讀 3408·2019-08-26 17:15
閱讀 3604·2019-08-26 13:49
閱讀 2630·2019-08-26 13:38
閱讀 2363·2019-08-26 12:08
閱讀 3294·2019-08-26 10:41
閱讀 1424·2019-08-26 10:24
閱讀 3433·2019-08-23 18:35