- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我有 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/
我有类似下面的代码: ... id: myComponent signal updateState() property variant modelList: [] Repeater { mo
我正在处理一些我无法展示的私有(private)代码,但我已经制作了一些示例代码来描述我的问题: 主.c: #include #include #include #include typede
这个问题在这里已经有了答案: 关闭10 年前。 Possible Duplicate: what are the differences in die() and exit() in PHP? 我想
在编写 Perl 模块时,在模块内部使用 croak/die 是一个好习惯吗? 毕竟,如果调用者不使用 eval block ,模块可能会使调用它的程序崩溃。 在这些情况下,最佳做法是什么? 最佳答案
我有一些搜索线程正在存储结果。我知道当线程启动时,JVM native 代码会代理在操作系统上创建新 native 线程的请求。这需要 JVM 之外的一些内存。当线程终止并且我保留对它的引用并将其用作
我刚刚花了很多时间调试一个我追溯到 wantarray() 的问题。 .我已将其提炼为这个测试用例。 (忽略 $! 在这种情况下不会有任何有用信息的事实)。我想知道为什么wantarray在第二个示例
我看到一些代码是这样做的: if(something){ echo 'exit from program'; die; } ...more code 和其他只使用 die 的人: if
我正在尝试将此表格用于: 如果任何 $_POST 变量等于任何其他 $_POST 变量抛出错误。 如果只有几个,那不是问题,但我有大约 20 个左右所以如果我想这样做,我将不得不像这样 但这
每次我运行: hadoop dfsadmin -report 我得到以下输出: Configured Capacity: 0 (0 KB) Present Capacity: 0 (0 KB) DFS
我是一名优秀的程序员,十分优秀!