findBug工具-Synchronization 相關(guān)問題的解決
1. findBug工具-Synchronization on Boolean(在Boolean類型的對象上使用了Synchronize關(guān)鍵字)
Bug原因:
在出現(xiàn)并發(fā)時,通過同步鎖使得只能由一個線程延遲加載一個或一組對象供后續(xù)使用(例如一個巨大的List或需要緩存的對象等等)。 然而,此前竟然從未意識到可能存在的嚴(yán)重問題西壮。
其中,規(guī)則制定者一書的作者認(rèn)為錯誤地在基本類型上使用synchronize關(guān)鍵字是導(dǎo)致并發(fā)問題的常見原因之一楣嘁,可能導(dǎo)致死鎖或其他不可預(yù)測的結(jié)果挤庇,并將其抽象為不應(yīng)該在任何可能被重用的對象[包括可能在JVM內(nèi)部重用的對象]上使用.
即Boolean類型的對象不可用于synchronization同步鎖寂祥。其問題的實(shí)質(zhì)在于Boolean.TRUE和Boolean.FALSE這兩個常量在JVM中實(shí)際是java.lang.Boolean類的兩個靜態(tài)成員變量顷啼,因而可能在程序中被多處引用踏枣。例如小压,當(dāng)上例中的inited指向Boolean.FALSE時,如果有其他的同步代碼塊在無意中使用了相同的Boolean常量椰于,那么就有可能導(dǎo)致死鎖。
2. findBug工具-Synchronizes on a boxed primitive object(在裝箱基本類型的對象上使用了Synchronize關(guān)鍵字)
上述代碼將int類型的count自動裝箱為Interger包裝類型的對象Lock仪搔,然后使用synchronize關(guān)鍵字對包裝類型的Lock變量加鎖瘾婿。可以預(yù)見烤咧,出于存儲和性能等等的考慮偏陪,在自動裝箱時JVM內(nèi)部必然會重用具有相同值類型的包裝類,因而Lock指向的對象極有可能被重用煮嫌,進(jìn)而在后續(xù)引發(fā)與Boolean類型變量存在的相同問題
3. findBug工具-Synchronizes on a interned String lock object(在內(nèi)部字符串對象上使用了Synchronize關(guān)鍵字)
根據(jù)Java API文檔笛谦,intern()方法實(shí)際是返回對象池中的對象,因而調(diào)用intern()方法后獲得到對象相當(dāng)于JVM中的一個全局變量昌阿。
所以饥脑,即便是像上述錯誤代碼中使用private和final關(guān)鍵字修飾lock變量,lock變量指向的仍然是同一個可能被重用的字符串常量懦冰。這種情況所帶來的問題與之前提到的兩種問題類似灶轰。
4. findBug工具-Synchronizes on a String Literal(在字符串常量上使用了Synchronize關(guān)鍵字)
基于之前的解釋很容易理解第四種情況,即JVM中的字符串常量是全局重用的刷钢。
終極解決方案
- 使用字符串實(shí)例
與字符串常量不同笋颤,字符串實(shí)例的引用是唯一的,因而不存在字符串常量可能導(dǎo)致的問題内地。
- 使用private final類型的java.lang.Object
CERT規(guī)范中提到伴澄,這種解決方法是少數(shù)可以直接利用到j(luò)ava.lang.Object的情況。在此處之所以強(qiáng)調(diào)使用Raw Object阱缓,同時還在CERT規(guī)范的原文中多次提到《Use private final lock objects to synchronize classes that may interact with untrusted code》非凌,是由于不使用Raw Object可能導(dǎo)致被exploit的問題,在此不再贅述茬祷。