上周,我們有幾個系統發生了線程死鎖,導致系統的請求被掛住,無法響應請求。后面查了一下該問題,原來是我廠一個基礎組件中使用的鎖對象不一致而導致了死鎖。
public class SimpleStore {
 
     
private Map sessions = Collections.synchronizedMap(new HashMap());
 
     
synchronized public void remove(String sessionID) { //A1
         sessions.put(sessionID, ""); //A2
         sessions.remove(sessionID);
         System.out.println(
"remove " + sessionID);
     }
 
     
public void commit(Map attrs, String sessionID, StatusHolder statusHolder) {
         System.out.println(
"commit " + sessionID);
         
synchronized (sessions) { //B1
             remove(sessionID); // B2
         }
     }
 }
上面代碼中:
 private Map sessions = Collections.synchronizedMap(new HashMap());

將sessions這個map申明為線程安全的map,則操作map中的任何方法時,都會加鎖,并且會鎖住sessions對象。  這行代碼,則在外部線程訪問remove方法時會鎖住SimpleStore這個對象。

 synchronized public void remove(String sessionID);

可以看到,目前在同一個類或者方法中,有兩把鎖,并且鎖對象不是同一個,那下面我們看看線程是怎么被死鎖住的:
1, 假設A線程先調用remove方法,則這時會把simpleStore給鎖住,然后執行sessions.put(sessionID, “”)的時候,會嘗試鎖住sessions
2, 同時B線程調用commit方法,在 synchronized (sessions) 時,會先鎖住sessions對象,并且在調用接下來的remove()試,會嘗試鎖住   SimpleStore對象,至此,線程A和線程B終于成功完成死鎖。

 

所以在使用多線程時一定要特別注意,使用鎖一定要注意你的鎖對象是否一致。要不然就有可能死鎖了~