上周,我们有几个系统发生了线程死锁,导致系统的请求被挂住,无法响应请求。后面查了一下该问题,原来是我厂一个基础组件中使用的锁对象不一致而导致了死锁。
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终于成功完成死锁。

 

所以在使用多线程时一定要特别注意,使用锁一定要注意你的锁对象是否一致。要不然就有可能死锁了~