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