两个常见的并发错误
作為Baeldung的編輯,我很高興與一位作者一起撰寫有關(guān)Java通用并發(fā)陷阱的文章。 這是一本不錯(cuò)的書,但是假設(shè)開發(fā)人員具有一定的能力。
我已經(jīng)看到了幾件即時(shí)并發(fā)失敗的事情。 它們很容易添加到代碼中,并保證為您提供奇怪的結(jié)果。 開發(fā)人員仍會提交這些事實(shí),這是對我們?nèi)绾螌O和并發(fā)進(jìn)行教育的一種評論,如果使用不當(dāng),這將非常危險(xiǎn)。
除了代碼審查
作為代碼審查員,這些年來我已經(jīng)開發(fā)了一些速記。 這些幫助我發(fā)現(xiàn)了在較大的代碼更改中需要更詳細(xì)地研究的區(qū)域。 它們包括紅旗的事情,我希望出問題。 訓(xùn)練自己去發(fā)現(xiàn)關(guān)鍵的反模式或潛在的反模式是一個(gè)好主意,因?yàn)樗鼈兛梢允怯行У拇a,但會導(dǎo)致無效的行為。
Bean中的請求狀態(tài)
在Java應(yīng)用程序中,服務(wù),控制器,處理程序和存儲庫通常是單例的。 它們是在應(yīng)用啟動(dòng)時(shí)創(chuàng)建的,然后請求通常通過多個(gè)線程傳遞給它們。
考慮如下代碼:
public void processOrder(Order order) { ... currentLineItem = order.getLine( 0 ); processLineItem(); } private void processLineItem() { myService.store(currentLineItem); }在這種情況下,該類的作者已決定該對象可以記住其當(dāng)前正在處理的項(xiàng)目,從而節(jié)省了將該項(xiàng)目傳遞給下一個(gè)函數(shù)的工作。
這違反了兩個(gè)原則:線程安全和有意義的對象狀態(tài)。 訂單處理者不太可能真正了解其正在處理的訂單。 您可能會想像一些有狀態(tài)地遍歷某個(gè)訂單,某種游標(biāo),閱讀器或構(gòu)建器的項(xiàng)目,但是將所有這些項(xiàng)目混合到一個(gè)對象中則很麻煩。
不過,最重要的是,有一個(gè)明確的定義可以解釋為什么這是錯(cuò)誤的。 如果將請求的每個(gè)屬性放入該請求的接收者中,那么您將有兩個(gè)風(fēng)險(xiǎn):
- 在多線程執(zhí)行中的請求之間出血
- 如果事情沒有完全整理,則在單線程的請求之間流血
簡而言之,永不做!
瘋狂的懶惰初始化
延遲初始化允許:
- 由于更快的啟動(dòng)
- 必要時(shí)及時(shí)加載資源
- 如果不需要,則不加載資源(例如,無服務(wù)器Lambda,在其生命周期中可能永遠(yuǎn)不會被要求執(zhí)行特定的代碼路徑)
- 定制如何通過較早發(fā)生的活動(dòng)加載資源
所有這些都很好。 但是,此代碼:
private LazyService getLazyService() { if (lazyService != null ) { return lazyService; } LazyService newLazyService = connectToLazyService(); registerWithServiceRegistry(newLazyService); lazyService = newLazyService; return newLazyService; }盡管它可以工作,但可以同時(shí)調(diào)用并出錯(cuò)。 它的錯(cuò)誤程度取決于各種各樣的事情。 在示例中,我試圖暗示我們正在處理的事情:
- 在并發(fā)調(diào)用中,發(fā)生了多個(gè)延遲加載…
- ……如果這很昂貴,那是浪費(fèi)
- 如果發(fā)生多個(gè)懶惰加載,則可能兩個(gè)對象在內(nèi)存中的駐留時(shí)間超過了所需時(shí)間,或者永遠(yuǎn)存在
- 如果這是單例,則獲取孤立對象的請求可能無法與其余請求協(xié)調(diào)
- 使用手工進(jìn)行的非線程安全的對象初始化真是遺憾
為了正確進(jìn)行單例初始化,您應(yīng)該使用雙重檢查鎖定或使用框架,甚至明智地使用基于static字段的簡單Java單例。
其他并發(fā)失敗
以上兩個(gè)似乎是最常見的錯(cuò)誤,以至于顯而易見。 如果發(fā)現(xiàn)另一個(gè),請將其放在評論中。
翻譯自: https://www.javacodegeeks.com/2020/01/two-common-concurrency-bugs.html
總結(jié)
- 上一篇: java8 默认方法_默认方法:Java
- 下一篇: jaxb_JAXB –新手的观点,第1部