jav*_*eek 7 java multithreading deadlock
我有2个帖子.一个线程打印奇数,第二个线程打印偶数.现在,我必须交替执行线程,以便我可以输出1,2,3,4,5,6,.....
我为此编写了一个程序,这导致了死锁.有人可以解释代码的问题是什么以及如何纠正它?
class BooleanObject {
boolean flag;
BooleanObject(boolean flag) {
this.flag = flag;
}
}
class EvenThread extends Thread {
Object lock;
BooleanObject flagObj;
EvenThread(Object o, BooleanObject flag) {
lock = o;
this.flagObj = flag;
}
public void run() {
for (int i=2;i<100;i+=2) {
synchronized(lock) {
if (flagObj.flag == false) {
flagObj.flag = true;
lock.notify();
}
else {
try {
while (flagObj.flag == true) {
lock.wait();
}
}
catch (InterruptedException e) {
}
}
System.out.println(i);
}
}
}
}
class OddThread extends Thread {
Object lock;
BooleanObject flagObj;
OddThread(Object o, BooleanObject flag) {
lock = o;
this.flagObj = flag;
}
public void run() {
for (int i=1;i<100;i+=2) {
synchronized(lock) {
if (flagObj.flag == true) {
flagObj.flag = false;
lock.notify();
}
else {
try {
while(flagObj.flag == false) {
lock.wait();
}
}
catch (InterruptedException e) {
}
}
System.out.println(i);
}
}
}
}
public class EvenOddThreads {
public static void main(String[] args) {
Object obj = new Object();
BooleanObject flagObj = new BooleanObject(true);
EvenThread et = new EvenThread(obj,flagObj);
OddThread ot = new OddThread(obj,flagObj);
et.setName("even thread");
ot.setName("odd thread");
et.start();
ot.start();
}
}
Run Code Online (Sandbox Code Playgroud)
问题出在自动装箱.当您flag从true 更改为false或反之时,您实际上正在获得一个全新的Boolean对象.就是这行:
flag = false;
Run Code Online (Sandbox Code Playgroud)
相当于:
flag = new Boolean(false);
Run Code Online (Sandbox Code Playgroud)
一旦发生这种情况,你的两个线程就会引用两个不同的Boolean对象,因此它们的标志最终会不同步,并且两个线程都不能发出信号通知另一个线程唤醒.当OddThread变化的标志EvenThread仍然有旧标志的对象,因此不会看到新的价值.
因为Boolean对象是不可变的,所以您需要更改标志以使用其他可变对象,这些对象可以在不创建新对象的情况下更改值.那,或者两个类都引用一个共同的(也许是全局的)变量.
正如@erickson建议你可以使用AtomicBoolean哪个是可变的.另一种做法的方法是flag改为:
boolean[] flag = new boolean[1];
Run Code Online (Sandbox Code Playgroud)
然后使用flag[0]每个地方.然后,两个线程都能够flag[0]在始终引用相同的boolean[]数组对象时进行更改.你不会有自动拳击问题.
...
此外,最好将任何调用包装wait()在循环中.wait()即使没有人实际呼叫,A 也可能受到虚假唤醒的影响notify().要解决这个问题,你应该在醒来后检查你的防护状态,以确保唤醒不是虚假的.
while (flag == true) {
lock.wait();
}
Run Code Online (Sandbox Code Playgroud)
我根据你上面的建议做了改动; 但我没有得到预期的输出.我将粘贴上面修改过的代码.这是我得到的输出1 2 4 3 5 6 8 7 9 10 11 13 12 15 17 14 ....
当你最后等待时,一旦你被唤醒,你不要切换flag并通知另一个线程.我建议重新组织你的代码,使它看起来像"等待;打印;通知".就像是:
synchronized (lock) {
while (flagObj.flag == false) {
lock.wait();
}
System.out.println(i);
flagObj.flag = false;
lock.notify();
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
803 次 |
| 最近记录: |