线程安全与并发编程探究(六)-死锁举例

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/dongping1023/article/details/47318413

      下面举一个发生死锁的代码案例,加深对并发安全的理解。

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等工具查看到线程死锁等待的具体信息。



猜你喜欢

转载自blog.csdn.net/dongping1023/article/details/47318413
今日推荐