英文:
Java thread synchronization gives weird output
问题
我旨在通过一个线程打印奇数,另一个线程打印偶数。下面的实现显示出奇怪的输出。请告诉我在这段代码中我漏掉了什么。
它按预期打印了 0 和 1。然后打印了 3 和 2。
// 期望输出 - > 012345678910
// 这段代码的实际输出 - > 013254769810 (流程在变化)
public class OddEvenNumberPrint {
public static boolean state = false; // 根据这个标志我会等待或通知
public static Object lock = new 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
英文:
My aim is to print odd numbers by one thread and even numbers by another thread.
Below implementation shows weird output. Please let me know what I am missing in this code.
It prints 0 and 1 as expected. Then it prints 3 and 2.
// Expected - > 012345678910
// Actual output by this code - > 013254769810 (Flow is changing)
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");
}
}
}
}
Output:
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
答案1
得分: 1
抱歉,我注意到您的要求是只返回翻译的部分,但是您的输入内容实际上已经相当详细。如果您有其他要求或者需要进一步的帮助,请随时提问。
英文:
Considering:
- Because
even
thread is created and started beforeodd
thread, so it doesn't meaneven
surely will acquire lock of mutex(lock
) first, NO!odd
has its chance to acquire it beforeeven
too. So possible to have1
and then0
- State management is the key in multi-threading, where your problem sits on it. Signaling must be done at right time/point.
The Problem
The problem with your code is signaling and state-management at wrong points, specially the start point for both threads look buggy.
Let's simulate the run:
Assuming even
thread get started and acquire that lock
first.
time 0. even
thread prints 0
|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 |
-------------+-------------------------+-------------------------+----------------
....
Please mind time 3
, and time 11
, that's because 1, then 3. Since even
thread has no chance to print 2
.
Now thinking, that odd
thread get started first before even
?
Hint: If thread B
must be started essentially after thread A
, the robust way is starting the thread B
from thread A
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论