gpt4 book ai didi

java - 线程死锁

转载 作者:塔克拉玛干 更新时间:2023-11-03 04:11:08 24 4
gpt4 key购买 nike

我有 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();
}
}

最佳答案

问题在于自动装箱。当您将 flag 从 true 更改为 false 或相反时,您实际上获得了一个全新的 Boolean 对象。也就是说,这一行:

flag = false;

相当于:

flag = new Boolean(false);

一旦发生这种情况,您的两个线程就会引用两个不同的 Boolean 对象,因此它们的标志最终会不同步,并且两个线程都无法向另一个线程发出唤醒信号。当 OddThread 更改标志时,EvenThread 仍然具有旧标志对象,因此它看不到新值。

因为 Boolean 对象是不可变的,所以您需要更改标志以使用其他一些可变对象,这些对象可以在不创建新对象的情况下就地更改值。那个,或者让两个类都引用一个公共(public)(可能是全局)变量。

正如@erickson 建议的那样,您可以使用可变的AtomicBoolean。另一种笨拙的方法是将 flag 更改为:

boolean[] flag = new boolean[1];

然后在每个地方使用 flag[0]。然后,两个线程都可以更改 flag[0],同时始终引用相同的 boolean[] 数组对象。你不会有自动装箱问题。

...

此外,将对 wait() 的任何调用包装在一个循环中是个好主意。 wait() 可能会受到虚假唤醒的影响,即使实际上没有人调用过 notify(),调用也会返回。要解决这个问题,您应该在醒来后始终检查您的保护状态,以确保唤醒不是虚假的。

while (flag == true) {
lock.wait();
}

更新

I have made the changes based on your suggestions above; but i am not getting the expected output. I will paste the modified code above. Here is the output i am getting 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();
}

关于java - 线程死锁,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2283479/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com