java多線程開發,鎖的管理

java多線程開發,死鎖一直是我們糾結的問題,當然,死鎖的時候查看線程信息是能找出個所以然來,但一旦到那個地步,估計整個程序架構出現的問題可能就不只一個地方。而解決死鎖的方法是注意鎖的順序問題,一個人開發當然好注意,但當多人開發時,這些問題都是會出現的,即使有良好的溝通,但總會出現一些小問題的,比如,A在方法funA1加了lock1,B在方法funB2加lock2,而funA1中需要調用到funB2,那麼,鎖的順序是lock1,lock2;然而,當B在方法funB3中加了lock2,而funB3又用到funA1,那鎖的順序是lock2,lock1。很明顯,一旦線程併發時,死鎖是會出現的。大家都以爲我把接口公佈給團隊裏的人就行了,他們不用管我裏面怎麼實現的,但事實就是這種想法在多線程編程裏面不太適合,至少我自己是認爲不太適合,我認爲涉及到鎖的地方,做爲一種編程習慣,不管你想與不想,你都得跟人家說,喂,你要調用我這個方法嗎,我給你調過,不過調過之前,不好意思,你先把我要的資源(鎖)給提供一下,但就算給你提供的時候,也難免會發生先lock1,lock2;然後有人先lock2,lock1。我之前也糾結於這個問題,後來我想到了一個鎖管理的辦法,至少這個辦法解決了上一個項目的死鎖問題,你可以不用java本身提供的鎖,繼承或聚合Lock寫一個類,我把它寫爲LevelLock,可以這麼寫

public class LevelLock implements Comparable<LevelLock>{
 private Lock lock;
 private int level;//鎖的級別
 private Comparable id;;/鎖的id,當鎖級別一個時,取id排序
 
 
 public LevelLock(Lock lock, int level, Comparable id){
  this.lock = lock;
  this.level = level;  

  this.id = id;

 }
 
 public void lock(){
  lock.lock();
 }
 
 public void unlock(){
  lock.unlock();
 }
 
 @Override
 public int compareTo(LevelLock lock) {
  if(lock.level > level)
   return -1;
  else if(lock.level < level)
   return 1;
  else{
   if(id == null)
    return 0;
   else{
    return id.compareTo(lock.id); 
   }
  }
 }

 public int getLevel() {
  return level;
 }

 public Comparable getId() {
  return id;
 }
 
 public String toString(){
  return level + "_" + id + "_" + lock;
 }
}

然後我們需要寫一個鎖管理類LockManager,如下

public class LockManager {
 private List<LevelLock> locks;
 
 public LockManager(List<LevelLock> locks){
  this.locks = locks;
  Collections.sort(locks);
 }
 
 public void lock(){
  Iterator<LevelLock> it = locks.iterator();
  LevelLock lock = null;
  while(it.hasNext()){
   lock = it.next();
   System.out.println(lock);
   lock.lock();
  }
 }
 
 public void unlock(){
  Iterator<LevelLock> it = locks.iterator();
  LevelLock lock = null;
  while(it.hasNext()){
   lock = it.next();
   System.out.println(lock);
   lock.unlock();
  }
 }
 
 public static void main(String args[]){
  List<LevelLock> locks = new ArrayList<LevelLock>();
  LevelLock lock1 = new LevelLock(new ReentrantLock(), 2, 0);
  LevelLock lock2 = new LevelLock(new ReentrantLock(), 1, 2);
  LevelLock lock3 = new LevelLock(new ReentrantLock(), 3, 0);
  LevelLock lock4 = new LevelLock(new ReentrantLock(), 1, 1);
  locks.add(lock1);
  locks.add(lock2);
  locks.add(lock3);
  locks.add(lock4);
  LockManager manager = new LockManager(locks);
  try{
   manager.lock();
  }finally{
   manager.unlock();
  }
 }
}

這樣,就差不多了,返回剛纔死鎖的問題,如果funA1調用funB2,時,直需要把lock1和lock2放到LockManager裏面就行了,LockManager會對傳進來的鎖進行排序,當然funB3調用funA1時也一樣,可能有人發現了manager.lock()沒放到try-catch-finally外面,以前一般都是

lock.lock();

try{

}finally{

lock.unlock();

}

這裏之所以不同,是因爲LockManager是對一組鎖進行管理,如果放到try-catch_finally外面的話,當lock1鎖住,lock2在加鎖的時候報錯,那麼,你永遠到不了finally那一塊,因爲manager.lock已經報錯了,沒到達try模塊,自然就到不了finally模塊,所以這裏有意這麼寫,還有manager.unlock()方法裏,必須按加鎖的順序解鎖,這跟上面說的問題一樣,一旦lock2加鎖時報錯,你必須保證lock1在finally裏得到解鎖,這是一樣的道理,當然,我不介意在finally裏面對lock2解鎖報錯,因爲已經不關緊要了,如果你認爲finally在解鎖lock2時報錯有關係,那麼,你可以對levelLock加多一個標誌,然後在lock後法標誌加上,unlock清除標誌,這也是可以的。其他的併發開發時的問題,再研究研究

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章