解决方案 »
- 编译出错?请教
- 怎样实现替换字符串中的子串
- 关于JTable的右键菜单!急啊
- 请教有关main method的问题
- javafx 的lookandfeel怎么弄成windows系统的?
- java2核心技术卷I II
- 谁有java方面的毕业论文?我想做此方面的,但手头一点资料都没有
- 页面特效的一个问题
- Exception in thread "main" java.lang.StackOverflowError
- tomcat使用jspSmartUpload组件,时不时的会发现内存暴涨,经过内存观察工具发现com.jspsmart.upload.file实例
- Test类究竟实现的是哪个接口中的方法
- 想自己用java 编辑一个记事本
while (a == 1)错误就是你这条件会造成所有线程最终等待;
按照刚开始的想法,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();
}
}
那么结果就总是顺利执行完毕。 第一次发帖,不知道怎么发代码,导致代码可读性这么差,谢谢你耐心看完。
按照刚开始的想法,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();
}
}
}
按照刚开始的想法,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方法来说吧,不知道你的实现怎样;
但若是上面同样实现代码,程序能运行的几率非常的低。
原因很简单:假如in1、in2、de1处于wait状态,del2执行完后如果唤醒的是del1的话,就in1、in2、de1、de2都wait了,死锁。所以只能换成notifyAll才能确保有in1或in2唤醒。
或者你可以用Lock来做,这个方便点。
void notifyAll(): 唤醒所有正在等待该对象的线程。两者的最大区别在于:notifyAll使所有原来在该对象上等待被notify的线程统统退出wait的状态,变成等待该对象上的锁,一旦该对象被解锁,他们就会去竞争。
notify他只是选择一个wait状态线程进行通知,并使它获得该对象上的锁,但不惊动其他同样在等待被该对象notify的线程们,当第一个线程运行完毕以后释放对象上的锁,此时如果该对象没有再次使用notify语句,即便该对象已经空闲,其他wait状态等待的线程由于没有得到该对象的通知,继续处在wait状态,直到这个对象发出一个notify或notifyAll,它们等待的是被notify或notifyAll,而不是锁。
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方法中添加的随机睡眠, 但是代码可以顺利的跑,跑了十几次了,全部跑完。
最后知道为什么会死锁之后,我更想明白为什么多了随机睡眠,就能顺利的跑完,不也应该会造成死锁的吗?
其实那只是恰好按照你期望的结果执行了,这种期望的结果只是在你当前机器的负荷下出现的概率比较大;
完全有可能发生你前面遇到的情况;
如:
若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));测试运行就会知道了;