上周,我們有幾個(gè)系統(tǒng)發(fā)生了線程死鎖,導(dǎo)致系統(tǒng)的請(qǐng)求被掛住,無(wú)法響應(yīng)請(qǐng)求。后面查了一下該問(wèn)題,原來(lái)是我廠一個(gè)基礎(chǔ)組件中使用的鎖對(duì)象不一致而導(dǎo)致了死鎖。
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這個(gè)map申明為線程安全的map,則操作map中的任何方法時(shí),都會(huì)加鎖,并且會(huì)鎖住sessions對(duì)象。 這行代碼,則在外部線程訪問(wèn)remove方法時(shí)會(huì)鎖住SimpleStore這個(gè)對(duì)象。
synchronized public void remove(String sessionID);
可以看到,目前在同一個(gè)類或者方法中,有兩把鎖,并且鎖對(duì)象不是同一個(gè),那下面我們看看線程是怎么被死鎖住的:
1, 假設(shè)A線程先調(diào)用remove方法,則這時(shí)會(huì)把simpleStore給鎖住,然后執(zhí)行sessions.put(sessionID, “”)的時(shí)候,會(huì)嘗試鎖住sessions
2, 同時(shí)B線程調(diào)用commit方法,在 synchronized (sessions) 時(shí),會(huì)先鎖住sessions對(duì)象,并且在調(diào)用接下來(lái)的remove()試,會(huì)嘗試鎖住 SimpleStore對(duì)象,至此,線程A和線程B終于成功完成死鎖。
所以在使用多線程時(shí)一定要特別注意,使用鎖一定要注意你的鎖對(duì)象是否一致。要不然就有可能死鎖了~