java线程的notify方法,wait方法
以下代码本以为会重复输出 01直到结束,但是实际结果是:有时候能顺利正确的执行完,也有时候会执行到一点就卡住
不再继续往下执行,只能强制关闭程序。
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 != 0)
{
try
{
wait();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
a++;
System.out.println(a);
notify();
}
public synchronized void decrease()
{
while(a == 0)
{
try
{
wait();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
a --;
System.out.println(a);
notify();
}
}
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++)
{
sample2.increase2();
}
}
}
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();
}
}
}
然后,我将Decrease和Increase类中的run()都修改成:
public void run()
{
for(int i = 0; i < 20; i++)
{
try
{
Thread.sleep((long)(Math.random() * 1000));
}
catch (InterruptedException e)
{
e.printStackTrace();
}
sample2.increase2();
}
}
最终结果就是正确的循环输出1010101010........。 本人初涉java,望大鸟门指点迷境。
------解决方案-------------------- 把notify改为notifyAll就行了
原因很简单:假如in1、in2、de1处于wait状态,del2执行完后如果唤醒的是del1的话,就in1、in2、de1、de2都wait了,死锁。所以只能换成notifyAll才能确保有in1或in2唤醒。
或者你可以用Lock来做,这个方便点。
------解决方案-------------------- 引用: sample2 increase2 decrease2 是我复制的时候弄错的。它们就是sample increase decrease,并没有改动。
改动的就只是在run方法中添加的随机睡眠, 但是代码可以顺利的跑,跑了十几次了,全部跑完。
最后知道为什么会死锁之后,我更想明白为什么多了随机睡眠,就能顺利的跑完,不也应该会造成死锁的吗?
其实那只是恰好按照你期望的结果执行了,这种期望的结果只是在你当前机器的负荷下出现的概率比较大;
完全有可能发生你前面遇到的情况;
如:
若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));
测试运行就会知道了;