两个线程 A 和 B 
A做加法   B做减法  
有时候正常无限计算下去
但有时 出现死锁  
死锁输出如下:  
 增加后结果:1
 增加后结果:2
 增加后结果:3
 增加后结果:4
 增加后结果:5
   add begin to wait 
代码如下:我就不明白  为什么会死锁?public class AddReduceTestAgain {
/**
 * @param args
 */
private int num = 0; private Add add = null; private Reduce reduce = null;
public static void main(String[] args) {
// TODO Auto-generated method stub
// Runnable r = new AddReduce();
AddReduceTestAgain ar = new AddReduceTestAgain(); Runnable r1 = ar.getAdd(ar); Runnable r2 = ar.getReduce(ar); Thread th1 = new Thread(r1, "th1");
Thread th2 = new Thread(r2, "th2"); th1.start();
th2.start(); } public Add getAdd(AddReduceTestAgain arTest) {
if (add == null) {
add = new Add(arTest);
}
return add;
} public Reduce getReduce(AddReduceTestAgain arTest) {
if (reduce == null) {
reduce = new Reduce(arTest);
}
return reduce;
} public void addMethord() {
while (num < 5) {
num += 1;
try {
Thread.currentThread().sleep(500);
} catch (Exception e) {
e.printStackTrace();
} synchronized (getAdd(AddReduceTestAgain.this)) {
System.out.println(" 增加后结果:" + num);
if (num >= 0)
getAdd(AddReduceTestAgain.this).notify();
} if (num >= 5) {
try {
synchronized (getReduce(AddReduceTestAgain.this)) {
System.out.println("   add begin to wait  ");
getReduce(AddReduceTestAgain.this).wait();  
}//这里执行完后已经 释放getReduce(AddReduceTestAgain.this)对象 } catch (InterruptedException e) {
e.printStackTrace();
}
}
}
} public void reduceMethod() {
while (num > 0) {
num -= 1;
try {
Thread.currentThread().sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
} synchronized (getReduce(AddReduceTestAgain.this)) { //为什么这里拿不到getReduce(AddReduceTestAgain.this)这个锁
System.out.println("减少后结果:" + num);
if (num < 5)
getReduce(AddReduceTestAgain.this).notify();
} if (num <= 0) {
try { synchronized (getAdd(AddReduceTestAgain.this)) { System.out.println("  reduce begin to wait  ");
getAdd(AddReduceTestAgain.this).wait();
} } catch (InterruptedException e) {
e.printStackTrace();
}
} } } class Add implements Runnable {
AddReduceTestAgain arTest = null; public Add(AddReduceTestAgain art) {
arTest = art;
} public void run() {
arTest.addMethord();
} } class Reduce implements Runnable {
AddReduceTestAgain arTest = null; public Reduce(AddReduceTestAgain art) {
arTest = art;
} public void run() {
arTest.reduceMethod();
} }}

解决方案 »

  1.   

    怎么没人进啊    把代码考下来放到eclipse里   我相信我遇到的这个问题要是解决了   大家都能学到不少东西
      

  2.   

    楼主的addMethod()和reduceMethod()方法里面有些奇怪。
    本人认为在这段代码中没有必要为getAdd()和getReduce,也就是add和reduce成员引用进行同步。因为这两个变量,两个线程分别指向它们其中之一。
    以下是我的代码: public void addMethord() { 
    int tempNum;
    while (true) {
    synchronized(num) {
    if(num < 5)
    num++;
    tempNum = num;
    }
    try { 
    Thread.sleep(500); 
    } catch (Exception e) { 
    e.printStackTrace(); 

    System.out.println(" 增加后结果:" + tempNum);
    try {
    if(num >= 5) {
    getReduce(this).notify();
    getAdd(this).wait();
    }
    }
    catch(InterruptedException e) {

    }
    catch(IllegalMonitorStateException e) {
    System.out.println("Thread add notifies Thread reduce!");
    }

    }  public void reduceMethod() { 
    int tempNum;
    while (true) { 
    synchronized(num) {
    if(num > 0)
    num--;
    tempNum = num;

    try { 
    Thread.sleep(500); 
    } catch (InterruptedException e) { 
    e.printStackTrace(); 

    System.out.println(" 减少后结果:" + tempNum);
    try {
    if (num <= 0) {
    getAdd(this).notify();
    getReduce(this).wait();
    }
    }
    catch(InterruptedException e) {

    }
    catch(IllegalMonitorStateException e) {
    System.out.println("Thread reduce notifies Thread add!");
    }


    另外,我对num用volatile进行了修饰。
    经过5次测试,没有发生死锁。
    以下输出结果是分别对getReduce(this).notify();和getAdd(this).notify();这两句加上断点后,在调试模式下测试的。也没有问题。 增加后结果:1
     减少后结果:0
     增加后结果:1
     减少后结果:0
     增加后结果:1
     减少后结果:0
     增加后结果:1
     减少后结果:0
     增加后结果:1
     减少后结果:0
     增加后结果:1
     减少后结果:0
     增加后结果:1
     减少后结果:0
     增加后结果:1
     减少后结果:0
     增加后结果:1
     减少后结果:0
     增加后结果:1
     减少后结果:0
     增加后结果:1
     减少后结果:0
     减少后结果:0
     增加后结果:1
     增加后结果:1
     增加后结果:2
     增加后结果:3
     增加后结果:4
     增加后结果:5
    Thread reduce notifies Thread add!
     减少后结果:4
     减少后结果:3
     减少后结果:2
     减少后结果:1
     减少后结果:0
    Thread add notifies Thread reduce!
     增加后结果:1
     增加后结果:2
     增加后结果:3
     增加后结果:4
     增加后结果:5
    Thread reduce notifies Thread add!
     减少后结果:4
     减少后结果:3
     减少后结果:2
     减少后结果:1
     减少后结果:0
      

  3.   

    Thread.currentThread().sleep(500);干吗要这条代码
    我是这么理解的num -= 1;后被另一个线程抢占,执行num += 1; 
    然后
    if (num > = 5) {
    try {
    synchronized (getReduce(AddReduceTestAgain.this)) {
    System.out.println("   add begin to wait  ");
    getReduce(AddReduceTestAgain.this).wait();  
    }//这里执行完后已经 释放getReduce(AddReduceTestAgain.this)对象} catch (InterruptedException e) {
    e.printStackTrace();
    } 不知道这样能不能得到锁!!!
      

  4.   

      谢谢    zenny_chen 
      我知道  我的问题出在哪了  基于你的code  我发现我遇到的不是死锁  而是在addMethord中 我的while执行结束了  也就是此时add线程已经执行完了  这个时候在reduceMethord调用add.notify也是没有用的    呵呵    你说的对    我的addMethord和reduceMethord别扭就别扭在while上
       
       对于这段code  wait和notify确实不用加同步块  因为add对象和reduce对象各只有一个线程再跑  而且我个人认为如果只有一个add对象的n个线程在跑和有只有一个reduce对象的n个线程在跑的话 都不用外wait和notify上加同步块   当多个add对象多个reduce对象及他们对应的线程时   此时wait和notify同步块必须加   不知道这句话对不对         不过我还是喜欢在wait()和notify上加同步块   %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% badonly   Thread.currentThread().sleep(500);    因为控制台显示结果太快了  让它慢点   让线程睡一会再打
              还有个问题   这是我第一次发帖   怎么给别人加分    -_-!