上周,我們有幾個系統發生了線程死鎖,導致系統的請求被掛住,無法響應請求。后面查了一下該問題,原來是我廠一個基礎組件中使用的鎖對象不一致而導致了死鎖。
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終于成功完成死鎖。
所以在使用多線程時一定要特別注意,使用鎖一定要注意你的鎖對象是否一致。要不然就有可能死鎖了~