A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

下面的代码,如果没有t3和t4这两个进程,程序输出的结果是 0 1 0 1 0 1 0 1 0 1 0 1 0 1 ……
                 加上t3和t4这两个进程之后,输出结果就乱了,没有任何规律。这是为什么?应该怎么改才能使输出结果变成 0 1 0 1 0 1 0 1 0 1 0 1 0 1 ……

看代码吧:
  1. public class MainTest
  2. {
  3. public static void main(String[] args)
  4. {
  5.   Sample sample = new Sample();
  6.   
  7.   Thread t1 = new IncreaseThread(sample);
  8.   Thread t2 = new DecreaseThread(sample);
  9.   
  10.   Thread t3 = new IncreaseThread(sample);
  11.   Thread t4 = new DecreaseThread(sample);
  12.   
  13.   t1.start();
  14.   t2.start();
  15.   t3.start();
  16.   t4.start();
  17. }
  18. }
复制代码
  1. public class IncreaseThread extends Thread
  2. {
  3. private Sample sample;

  4. public IncreaseThread(Sample sample)
  5. {
  6.   this.sample = sample;
  7. }

  8. public void run()
  9. {
  10.   for(int i=0 ; i<20 ; i++)
  11.   {
  12.    try
  13.    {
  14.     Thread.sleep((long)(Math.random()*1000));
  15.    } catch (InterruptedException e)
  16.    {
  17.     e.printStackTrace();
  18.    }
  19.    
  20.    sample.increase();
  21.   }
  22. }
  23. }
复制代码
  1. public class DecreaseThread extends Thread
  2. {
  3. private Sample sample;

  4. public DecreaseThread(Sample sample)
  5. {
  6.   this.sample = sample;
  7. }

  8. public void run()
  9. {
  10.   for(int i=0 ; i<20 ; i++)
  11.   {
  12.    try
  13.    {
  14.     Thread.sleep((long)(Math.random()*1000));
  15.    } catch (InterruptedException e)
  16.    {
  17.     e.printStackTrace();
  18.    }
  19.    
  20.    sample.decrease();
  21.   }
  22. }
  23. }
复制代码
  1. public class Sample
  2. {
  3. private int number;

  4. public synchronized void increase()
  5. {
  6.   if(0 != number)
  7.   {
  8.    try
  9.    {
  10.     wait();
  11.    } catch (InterruptedException e)
  12.    {
  13.     e.printStackTrace();
  14.    }
  15.   }
  16.   
  17.   number++;
  18.   
  19.   System.out.println(number);
  20.   
  21.   notify();
  22. }

  23. public synchronized void decrease()
  24. {
  25.   if(0 == number)
  26.   {
  27.    try
  28.    {
  29.     wait();
  30.    } catch (InterruptedException e)
  31.    {
  32.     e.printStackTrace();
  33.    }
  34.   }
  35.   
  36.   number--;
  37.   
  38.   System.out.println(number);
  39.   
  40.   notify();
  41. }
  42. }
复制代码

4 个回复

倒序浏览
public class Sample
{
private int number;
public synchronized void increase()
{
  if(0 != number)
  {
   try
   {
    wait();
   } catch (InterruptedException e)
   {
    e.printStackTrace();
   }
  }
  
  number++;
  
  System.out.println(number);
  
notify();
}
public synchronized void decrease()
{
if(0 == number)
  {
   try
   {
    wait();
   } catch (InterruptedException e)
   {
    e.printStackTrace();
   }
  }
  
  number--;
  
  System.out.println(number);
  
  notify();
}
}


Thread t1 = new IncreaseThread(sample);
Thread t2 = new DecreaseThread(sample)
Thread t3 = new IncreaseThread(sample);
Thread t4 = new DecreaseThread(sample);
先说说怎么改:你只需要把if,改为while.notify改为notifyAll。就行了。
再说说你的为什么会乱:假如这种情况,当开始0 == number时,执行 if(0 == number)的时候,你的t2,t4个线程执行number--时,你会发现他们都在if中wait()了。然后 t1 线程执行 if(0 != number)时,t1就把t2的唤醒,然后t1也wait(),现在还能有执行权的是t2和t3。然后t3执行,因为现在number=1。所以t3,也wait()。现在就剩t2了。
注意:由于t2执行时,就会把t4唤醒,由于是if条件语句,t4就不会去判断if(0 == number)。所有t4就会继续执行下去。所以执行了2次number--。所以你的程序就乱了。
最后说说为什么这么改:由上面分析,你应该知道,t4唤醒时,还要去判断下,所以if就改为while。但用while是,会出现死锁。所以就把notify,改为notifyAll。因为每个线程唤醒时,都会去判断条件,所有之后就不会乱了。

回复 使用道具 举报
刘源 发表于 2012-8-23 10:04
public class Sample
{
private int number;

你真厉害。我看懂了。只是不太明白notify和notifyAll的区别是什么?为什么你说使用notifyAll就不会出现死锁?
回复 使用道具 举报
notify:一次只能唤醒一个,就是把最先wait(),的那个线程唤醒。
notifyAll:而它就是把所有wait()的线程全部唤醒。你想啊,每次他都把你4个线程都唤醒了,肯定不会出现4个线程都wait()的情况啊
回复 使用道具 举报
刘源 发表于 2012-8-23 10:18
notify:一次只能唤醒一个,就是把最先wait(),的那个线程唤醒。
notifyAll:而它就是把所有wait()的线程全部 ...

明白了。谢谢。问题已解决。
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马