解决方案 »

  1.   

    你把increase方法的条件改成下面的:
    while (a == 1)错误就是你这条件会造成所有线程最终等待;
      

  2.   


    按照刚开始的想法,a的值不是1就是0,所以我写while( a != 0 )。然后我按你说了改成了while( a == 1),程序执行结果依然是所有线程都最终等待。    但是我只要把run方法,改成;public void run()
    for(int i = 0; i < 20; i++)
    {
    try
    {
    Thread.sleep((long)(Math.random() * 1000));
    }
    catch (InterruptedException e)
    {
    e.printStackTrace();
    }
    sample2.decrease2();
    }
    }
    那么结果就总是顺利执行完毕。    第一次发帖,不知道怎么发代码,导致代码可读性这么差,谢谢你耐心看完。
      

  3.   


    按照刚开始的想法,a的值不是1就是0,所以我写while( a != 0 )。然后我按你说了改成了while( a == 1),程序执行结果依然是所有线程都最终等待。    但是我只要把run方法,改成;public void run()
    for(int i = 0; i < 20; i++)
    {
    try
    {
    Thread.sleep((long)(Math.random() * 1000));
    }
    catch (InterruptedException e)
    {
    e.printStackTrace();
    }
    sample2.decrease2();
    }
    }
    那么结果就总是顺利执行完毕。    第一次发帖,不知道怎么发代码,导致代码可读性这么差,谢谢你耐心看完。你上面的increase2 和 decrease2方法是哪里来的???
    还有要把那个notify改为notifyAll:public class B02Notify {
    public static void main(String[] args) {
    Sample sample = new Sample(); Increase in1 = new Increase(sample);
    Increase in2 = new Increase(sample);
    Decrease de1 = new Decrease(sample);
    Decrease de2 = new Decrease(sample); in1.start();
    de1.start();
    in2.start();
    de2.start();
    }
    }class Sample {
    private int a; public synchronized void increase() {
    while (a == 1) {
    try {
    wait();
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    } a++;
    System.out.println(a); notifyAll(); } public synchronized void decrease() {
    while (a == 0) {
    try {
    wait();
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    } a--;
    System.out.println(a); notifyAll();
    }
    }class Increase extends Thread {
    private Sample sample; public Increase(Sample sample) {
    this.sample = sample;
    } @Override
    public void run() {
    for (int i = 0; i < 20; i++) {
    sample.increase();
    }
    }
    }class Decrease extends Thread {
    private Sample sample; public Decrease(Sample sample) {
    this.sample = sample;
    } @Override
    public void run() {
    for (int i = 0; i < 20; i++) {
    sample.decrease();
    }
    }
    }
      

  4.   


    按照刚开始的想法,a的值不是1就是0,所以我写while( a != 0 )。然后我按你说了改成了while( a == 1),程序执行结果依然是所有线程都最终等待。    但是我只要把run方法,改成;public void run()
    for(int i = 0; i < 20; i++)
    {
    try
    {
    Thread.sleep((long)(Math.random() * 1000));
    }
    catch (InterruptedException e)
    {
    e.printStackTrace();
    }
    sample2.decrease2();
    }
    }
    那么结果就总是顺利执行完毕。    第一次发帖,不知道怎么发代码,导致代码可读性这么差,谢谢你耐心看完。
    你说顺利的结果是针对你的increase2 和 decrease2方法来说吧,不知道你的实现怎样;
    但若是上面同样实现代码,程序能运行的几率非常的低。
      

  5.   

    把notify改为notifyAll就行了
    原因很简单:假如in1、in2、de1处于wait状态,del2执行完后如果唤醒的是del1的话,就in1、in2、de1、de2都wait了,死锁。所以只能换成notifyAll才能确保有in1或in2唤醒。
    或者你可以用Lock来做,这个方便点。
      

  6.   

    notify()和notifyAll()都是Object对象用于通知处在等待该对象的线程的方法。void notify(): 唤醒一个正在等待该对象的线程。
    void notifyAll(): 唤醒所有正在等待该对象的线程。两者的最大区别在于:notifyAll使所有原来在该对象上等待被notify的线程统统退出wait的状态,变成等待该对象上的锁,一旦该对象被解锁,他们就会去竞争。
    notify他只是选择一个wait状态线程进行通知,并使它获得该对象上的锁,但不惊动其他同样在等待被该对象notify的线程们,当第一个线程运行完毕以后释放对象上的锁,此时如果该对象没有再次使用notify语句,即便该对象已经空闲,其他wait状态等待的线程由于没有得到该对象的通知,继续处在wait状态,直到这个对象发出一个notify或notifyAll,它们等待的是被notify或notifyAll,而不是锁。 
      

  7.   

    按照刚开始的想法,a的值不是1就是0,所以我写while( a != 0 )。然后我按你说了改成了while( a == 1),程序执行结果依然是所有线程都最终等待。    但是我只要把run方法,改成;public void run()
    for(int i = 0; i < 20; i++)
    {
    try
    {
    Thread.sleep((long)(Math.random() * 1000));
    }
    catch (InterruptedException e)
    {
    e.printStackTrace();
    }
    sample2.decrease2();
    }
    }
    那么结果就总是顺利执行完毕。    第一次发帖,不知道怎么发代码,导致代码可读性这么差,谢谢你耐心看完。
    你说顺利的结果是针对你的increase2 和 decrease2方法来说吧,不知道你的实现怎样;
    但若是上面同样实现代码,程序能运行的几率非常的低。sample2 increase2 decrease2  是我复制的时候弄错的。它们就是sample increase decrease,并没有改动。
    改动的就只是在run方法中添加的随机睡眠, 但是代码可以顺利的跑,跑了十几次了,全部跑完。  
    最后知道为什么会死锁之后,我更想明白为什么多了随机睡眠,就能顺利的跑完,不也应该会造成死锁的吗?
      

  8.   


    其实那只是恰好按照你期望的结果执行了,这种期望的结果只是在你当前机器的负荷下出现的概率比较大;
    完全有可能发生你前面遇到的情况;
    如:  
    若de1  de2先运行,并进入sleep;
    接着 in1  in2运行进入sleep;
    接着操作系统繁忙,在de1  de2进入可运行状态时,没有运行;
    接着 in1  in2进入可运行状态;
    这样in1, in2,de1 , de2都是可运行状态;
    这时若操作系统运行de1进入等待,运行de2进入等待,接着运行 in1 加1后唤醒de1,再次进入sleep(可以看成一个时间片断内),接着运行in2 进入等待,这时 in1 进入可运行状态并运行 in1 进入等待,唤醒的 de1 运行减一并唤醒de2,再次进入sleep,这时运行de2进入等待,de1进入可运行状态并运行de1进入等待;这其实与线程的调度有关:线程的调度是由操作系统控制的,而且是抢占式调度;你要想使发生的几率变大,只需把睡眠时间改小就可以了:
    如Increase改为:
    Thread.sleep((long) (Math.random() * 10));如Decrease改为:
    Thread.sleep((long) (Math.random() * 15));测试运行就会知道了;