Java并發編程:wait/notifyall機制的鎖對象為何不能是業務對象?
在Java并發編程中,wait()和notifyAll()方法的正確使用至關重要。本文將解釋為什么這些方法的鎖對象不能是業務對象,并以廚師做菜、食客吃菜的例子說明。
假設場景:廚師做菜,食客吃菜。直覺上,菜的數量(food)似乎應該作為鎖對象。然而,最佳實踐是使用一個獨立的Object作為鎖,而不是food本身。這是為什么呢?
問題根源在于synchronized關鍵字的鎖機制作用于對象本身,而非對象的值。如果food是一個Integer對象,當廚師修改food的值時(例如,從0變成1),鎖對象并沒有改變,仍然是同一個Integer對象。但是,wait()方法依賴于鎖對象進行等待。如果使用food作為鎖,當廚師修改food值后,食客線程仍然持有舊的food對象鎖,無法被喚醒,導致程序出現問題。
更進一步,Integer對象的緩存機制會加劇這個問題。在-128到127的范圍內,多個值為0的Integer對象可能指向同一個對象。但超過這個范圍,則會創建新的Integer對象。因此,使用food作為鎖存在嚴重的線程安全隱患。
立即學習“Java免費學習筆記(深入)”;
為了避免死鎖或數據不一致,最佳實踐是使用一個獨立的Object對象作為鎖。這個鎖對象與業務數據(food)無關,只負責協調線程同步。廚師和食客線程都獲取同一個Object鎖,保證線程間的正確同步和喚醒。
使用獨立鎖對象確保業務數據變化時,等待線程能被正確喚醒,避免因鎖對象變化導致的線程同步問題。這強調了在并發程序設計中,將鎖對象與業務數據分離的重要性,從而保證程序的正確性和穩定性。