線程安全與併發編程探究(六)-死鎖舉例

      下面舉一個發生死鎖的代碼案例,加深對併發安全的理解。

package cn.zhou;
import java.util.concurrent.CountDownLatch;
/**
線程死鎖等待舉例
 * 可以通過JConsole命令工具     去查看
**/
public class SynAddDeadLock implementsRunnable{
       private int a,b;
       CountDownLatch countDownLatch;
       publicSynAddDeadLock(int a,int b,CountDownLatch doneSignal){
              this.a = a;
              this.b = b;
              countDownLatch =doneSignal;
       }
       @Override
       public void run(){
              synchronized(Integer.valueOf(a)) {
                     synchronized(Integer.valueOf(b)) {
                            System.out.println(Thread.currentThread().getName()+"---"+(a+b));
                     }
              }
              countDownLatch.countDown();
       }
       public static voidmain(String[] args) {
 
              final intthreadCount = 200;
              booleanisDeadLock = false;
              CountDownLatch doneSignal = newCountDownLatch(threadCount);
              for (int i = 0;i < threadCount/2; i++) {
                     newThread(new SynAddDeadLock(1, 2,doneSignal)).start();
                     newThread(new SynAddDeadLock(2,1,doneSignal)).start();
              }
              isDeadLock = true;
              try {
                     System.out.println("has deadlock");
                     doneSignal.await();
                     //若所有線程都已經結束 說明不存在死鎖
                     isDeadLock = false;
              } catch(InterruptedException e) {
                     e.printStackTrace();
              }
              if(!isDeadLock){
                     System.out.println("no deadlock");
              }
              System.out.println("end");
       }
}


分析:開啓200個線程分別計算1+2以及2+1的值,其實for循環是可以省略的,兩個線程也可能會導致死鎖,不過那樣概率太小,需要嘗試很多次才能看到效果。一般的話,帶for循環的(如上所述)的版本最多運行2~3次就會遇到死鎖,程序無法結束。

造成死鎖的原因是:Integer.valueOf()方法基於減少對象創建次數和節省內存的考慮,【-128,127】之間的數字會被緩存(默認值,實際值取決於java.lang.Integer.IntegerCache.high參數的設置),當valueOf方法傳入參數在這個範圍之內,將之間返回緩存中的對象。即 代碼中調用了200次的Integer.valueOf()方法一共只返回了兩個不同的對象(1和2).假如在某個線程的兩個synchronized塊之間發生了一次線程切換,那就會出現線程A等着被線程B持有的Integer.valueof(1),線程B又等着被線程A持有的Integer.valueOf(2)結果出現都跑不下去的情景。另外,我們可以可以通過Jconsole jviauslvm等工具查看到線程死鎖等待的具體信息。



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