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

 

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