问题描述
我的目的是通过一个线程打印奇数,而通过另一个线程打印偶数。 下面的实现显示了奇怪的输出。请让我知道这段代码中缺少的内容。
它按预期打印0和1。然后打印3和2。
//预期-> 012345678910
//此代码的实际输出-> 013254769810(流量正在变化)
public class OddEvennumberPrint {
public static boolean state = false; // based on this flag I will wait or notify
public static Object lock = new Object(); // the common locking object
public static void main(String[] args) {
EvenThread t1 = new EvenThread("Even");
t1.start();
OddThread t2 = new OddThread("Odd");
t2.start();
}
}
class EvenThread extends Thread {
public EvenThread(String name) {
this.setName(name);
}
public void run() {
for (int i = 0; i <= 10; i = i + 2) {
synchronized (OddEvennumberPrint.lock) {
System.out.println("Even ->"+i);
while (!OddEvennumberPrint.state) {
try {
System.out.println(Thread.currentThread().getName()+ " : "+ "Going wait");
OddEvennumberPrint.lock.wait();
} catch (InterruptedException e) {
e.printstacktrace();
}
}
OddEvennumberPrint.state = false;
OddEvennumberPrint.lock.notify();
System.out.println(Thread.currentThread().getName()+ " : "+ "Released");
}
}
}
}
class OddThread extends Thread {
public OddThread(String name) {
this.setName(name);
}
public void run() {
for (int i = 1; i < 10; i = i + 2) {
synchronized (OddEvennumberPrint.lock) {
System.out.println("Odd -> "+i);
while (OddEvennumberPrint.state) {
try {
System.out.println(Thread.currentThread().getName()+ " : "+ "Going wait");
OddEvennumberPrint.lock.wait();
} catch (InterruptedException e) {
e.printstacktrace();
}
}
OddEvennumberPrint.state = true;
OddEvennumberPrint.lock.notify();
System.out.println(Thread.currentThread().getName()+ " : "+ "Released");
}
}
}
}
输出:
Even ->0
Even : Going wait
Odd -> 1
Odd : Released
Odd -> 3
Odd : Going wait
Even : Released
Even ->2
Even : Going wait
Odd : Released
Odd -> 5
Odd : Going wait
Even : Released
Even ->4
Even : Going wait
Odd : Released
Odd -> 7
Odd : Going wait
Even : Released
Even ->6
Even : Going wait
Odd : Released
Odd -> 9
Odd : Going wait
Even : Released
Even ->8
Even : Going wait
Odd : Released
Even : Released
Even ->10
Even : Going wait
解决方法
考虑:
- 因为
even
线程是在odd
线程之前创建和启动的,所以它不是意味着even
肯定会获得互斥锁({{1 }})首先,不!lock
也有机会在odd
之前获得它。因此可以先拥有even
,然后拥有1
- 状态管理是多线程的关键,而问题就出在这里。信号必须在正确的时间/点完成。
问题
您的代码的问题是在错误的点发出信号和进行状态管理,特别是两个线程的起点看起来都是错误的。
让我们模拟跑步:
假设0
线程开始并首先获取该even
。
时间0。lock
线程输出0
even
请注意 |Even Thread |Odd Thread |lock/mutex
-------------+-------------------------+-------------------------+----------------
time 0 |acquires lock of mutex |blocked,cannot acquire |false
| |lock of mutex |
-------------+-------------------------+-------------------------+----------------
time 1 |prints (next even 0,...) |still waiting... |false
-------------+-------------------------+-------------------------+----------------
time 2 |going to unlock mutex |acquires lock of mutex |false
|and wait for a signal |as it's unlocked from |
|becasue lock == false |even |
-------------+-------------------------+-------------------------+----------------
time 3 |still waiting... |prints (next odd 1,...) |false
-------------+-------------------------+-------------------------+----------------
time 4 |still waiting... |won't wait for a signal |false
| |since lock is false |
-------------+-------------------------+-------------------------+----------------
time 5 |still waiting... |set the lock state to |true
| |true |
-------------+-------------------------+-------------------------+----------------
time 6 |still waiting... |notify on mutex,but |true
|Got one signal on mutex |WON'T unlock it yet |
|but CANNOT continue as | |
|it's not release yet | |
-------------+-------------------------+-------------------------+----------------
time 7 |Can get lock of mutext |one loop has finished |true
|as odd released it |now try to acquire the |
|now can continue |mutex again,but cannot |
| |since it just got locked |
| |by even thread |
-------------+-------------------------+-------------------------+----------------
time 8 |set the lock state to |still waiting... |false
|false | |
-------------+-------------------------+-------------------------+----------------
time 9 |notify on mutex,but |still waiting... |false
|WON'T unlock it yet |Got one signal on mutex |
| |but CANNOT continue as |
| |it's not release yet |
-------------+-------------------------+-------------------------+----------------
time 10 |one loop has finished |Can get lock of mutext |false
|now try to acquire the |as even released it |
|mutex again,but cannot |now can continue |
|since it just got locked | |
|by odd thread | |
-------------+-------------------------+-------------------------+----------------
time 11 |still waiting... |prints (next odd 3) |false
|to acquire lock,not a | |
|signal | |
-------------+-------------------------+-------------------------+----------------
time 12 |still waiting... |won't wait for a signal |false
| |since lock is false |
-------------+-------------------------+-------------------------+----------------
....
和time 3
,这是因为1,然后是3。由于time 11
线程没有机会打印even
。
现在正在考虑,2
线程是在odd
之前首先启动的吗?
提示::如果必须在线程even
之后实质上启动线程B
,则可靠的方法是从线程A
启动线程B
。