使用Java中的2个线程打印奇数数字
我确定我的问题有多个答案。但是,我正在学习多线程的基本概念,我想到了以下代码。
有两个线程:一个打印均匀的数字,另一个打印奇数。由于某种原因,他们首先打印出正确的数字,然后“交换”角色。而且,它们似乎不仅打印了前10个数字。
为什么不给出正确的输出?
package com.thread;
public class OddEventThread {
public static void main(String[] args) {
SharedResource obj = new SharedResource();
OddThread oddThread = new OddThread(obj);
EvenThread evenThread = new EvenThread(obj);
System.out.println("Starting Odd/Even Thread");
oddThread.start();
evenThread.start();
}
}
class OddThread extends Thread {
SharedResource obj;
public OddThread(SharedResource obj) {
this.obj = obj;
}
@Override
public void run() {
System.out.println("OddThread");
obj.printOdd();
}
}
class EvenThread extends Thread {
SharedResource obj;
public EvenThread(SharedResource obj) {
this.obj = obj;
}
@Override
public void run() {
System.out.println("EvenThread");
obj.printEven();
}
}
class SharedResource {
private int N = 10;
private int counter = 1;
public void printOdd() {
System.out.println("printOdd");
synchronized (this) {
System.out.println("OddThread: Counter: " + counter);
while (counter <= N) {
if (counter % 2 != 0) {
System.out.println(counter);
} else {
try {
System.out.println("OddThread: Wait: Counter: " + counter);
wait();
} catch (InterruptedException e) {
System.out.println("Interrupted Exception!");
}
}
counter++;
System.out.println("OddThread: Notify: Counter: " + counter);
notify();
}
}
}
public void printEven() {
System.out.println("printEven");
synchronized (this) {
System.out.println("EvenThread: Counter: " + counter);
while (counter <= N) {
if (counter % 2 == 0) {
System.out.println(counter);
} else {
try {
System.out.println("EvenThread: Wait: Counter: " + counter);
wait();
} catch (InterruptedException e) {
System.out.println("Interrupted Exception!");
}
}
counter++;
System.out.println("EvenThread: Notify: Counter: " + counter);
notify();
}
}
}
}
输出:
Starting Odd/Even Thread
OddThread
printOdd
EvenThread
printEven
OddThread: Counter: 1
1
OddThread: Notify: Counter: 2
OddThread: Wait: Counter: 2
EvenThread: Counter: 2
2
EvenThread: Notify: Counter: 3
EvenThread: Wait: Counter: 3
OddThread: Notify: Counter: 4
OddThread: Wait: Counter: 4
EvenThread: Notify: Counter: 5
EvenThread: Wait: Counter: 5
OddThread: Notify: Counter: 6
OddThread: Wait: Counter: 6
EvenThread: Notify: Counter: 7
EvenThread: Wait: Counter: 7
OddThread: Notify: Counter: 8
OddThread: Wait: Counter: 8
EvenThread: Notify: Counter: 9
EvenThread: Wait: Counter: 9
OddThread: Notify: Counter: 10
OddThread: Wait: Counter: 10
EvenThread: Notify: Counter: 11
OddThread: Notify: Counter: 12
这是我提出此解决方案的思考过程:
我们有2个线程从1到10打印数字。这两个线程都应共享一个对象,因此我想出了一个共享obj。因此,由于在2个线程之间共享相同的对象,因此同步块应在正确更新该值方面起作用。
I'm sure there are multiple answers to my question. But, I am learning the basic concepts of multi-threading and I came up with the code below.
There are two threads: one prints even numbers and the other prints odd numbers. For some reason, they both print their right number at first and then they "swap" role. Also, they seem to print more than just the first 10 numbers.
Why is it not giving the correct output?
package com.thread;
public class OddEventThread {
public static void main(String[] args) {
SharedResource obj = new SharedResource();
OddThread oddThread = new OddThread(obj);
EvenThread evenThread = new EvenThread(obj);
System.out.println("Starting Odd/Even Thread");
oddThread.start();
evenThread.start();
}
}
class OddThread extends Thread {
SharedResource obj;
public OddThread(SharedResource obj) {
this.obj = obj;
}
@Override
public void run() {
System.out.println("OddThread");
obj.printOdd();
}
}
class EvenThread extends Thread {
SharedResource obj;
public EvenThread(SharedResource obj) {
this.obj = obj;
}
@Override
public void run() {
System.out.println("EvenThread");
obj.printEven();
}
}
class SharedResource {
private int N = 10;
private int counter = 1;
public void printOdd() {
System.out.println("printOdd");
synchronized (this) {
System.out.println("OddThread: Counter: " + counter);
while (counter <= N) {
if (counter % 2 != 0) {
System.out.println(counter);
} else {
try {
System.out.println("OddThread: Wait: Counter: " + counter);
wait();
} catch (InterruptedException e) {
System.out.println("Interrupted Exception!");
}
}
counter++;
System.out.println("OddThread: Notify: Counter: " + counter);
notify();
}
}
}
public void printEven() {
System.out.println("printEven");
synchronized (this) {
System.out.println("EvenThread: Counter: " + counter);
while (counter <= N) {
if (counter % 2 == 0) {
System.out.println(counter);
} else {
try {
System.out.println("EvenThread: Wait: Counter: " + counter);
wait();
} catch (InterruptedException e) {
System.out.println("Interrupted Exception!");
}
}
counter++;
System.out.println("EvenThread: Notify: Counter: " + counter);
notify();
}
}
}
}
Output:
Starting Odd/Even Thread
OddThread
printOdd
EvenThread
printEven
OddThread: Counter: 1
1
OddThread: Notify: Counter: 2
OddThread: Wait: Counter: 2
EvenThread: Counter: 2
2
EvenThread: Notify: Counter: 3
EvenThread: Wait: Counter: 3
OddThread: Notify: Counter: 4
OddThread: Wait: Counter: 4
EvenThread: Notify: Counter: 5
EvenThread: Wait: Counter: 5
OddThread: Notify: Counter: 6
OddThread: Wait: Counter: 6
EvenThread: Notify: Counter: 7
EvenThread: Wait: Counter: 7
OddThread: Notify: Counter: 8
OddThread: Wait: Counter: 8
EvenThread: Notify: Counter: 9
EvenThread: Wait: Counter: 9
OddThread: Notify: Counter: 10
OddThread: Wait: Counter: 10
EvenThread: Notify: Counter: 11
OddThread: Notify: Counter: 12
Here is my thought process of coming up with this solution:
we have 2 threads which print numbers from 1 to 10. Both threads should share an object, hence I came up with one sharedObj. So, since the same object is shared between 2 threads, then the synchronized block should work in properly updating the value.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
代码问题
您的设计和一般逻辑存在一些问题。
在您的代码中,基本上有两个类别做完全相同的类:打印数字。唯一不同的条件是:印刷数字是否必须奇怪甚至。您已经可以使用一个
thread
类来实现这一目标,其中唯一要参数化的是打印条件。printodd()
和printeven()
方法几乎是复制/粘贴。此外,关注点的分离不能正确处理。您的
sharedObject
类基本上是一个计数器,它不仅可以保持跟踪和增加计数值,而且还必须处理两个线程的逻辑,这是不应该落在其上的东西。它的唯一目标应该是以一致的方式和并行执行以一致的方式递增共享值。您应该在thread
中重定向该打印逻辑,因为如您所见,它们的代码基本上是在拨打单个呼叫中。在您的代码中分解代码
,两个线程都仅在开始时就打印了正确的数字(
system.out.println
没有任何文本),因为:sharedObject < /code>的监视器,假设
oddThread
,这意味着EventHread
等待锁定版本以输入同步块。此时,OddThread
打印其相应的数字(1):oddThread
将值递增到2,打印Notify语句,最后通知另一个线程。请记住,当该线程正在执行所有操作时,它仍然拥有sharedObject
的监视器。oddthread
发布锁定并等待,直到eventhread
通知。EventHread
最终可以输入同步语句并打印其值(2)。EventHread
将值递增到3,用值3打印Notify语句(因此它的打印两次,也是错误的数字),最后是通知另一个线程。eventHread
测试时
条件,失败如果语句,打印等待语句,然后等待oddthread
唤醒它。Wait()
Invocation 继续。当数字是正确的“类型”时,他们俩都恢复,将值(使其相对类型)增加,然后打印Notify语句。这不仅说明了为什么每个线程都会打印其相对的数字类型,而且还解释了为什么即使达到10最大值10之后,它们也会继续打印。在迭代时,他们都在到达最后一个后又增加了一次,因为他们都从最后一个
wait()
调用中恢复。解决
方案是解决上述问题的实现。
Code Issues
There are some issues in your implementation regarding the design and general logic.
In your code, there are two classes that basically do the exact same thing: printing numbers. The only thing that differs is the condition: whether the printed numbers must be odd or even. You could already achieve this with one
Thread
class, where the only thing to parameterize is the printing condition. TheprintOdd()
andprintEven()
methods are almost a copy/paste.Furthermore, the separation of concerns is not dealt properly. Your
SharedObject
class is basically a counter, which not only keeps track and increments the counting value, but it has also to deal with both threads' logic, which is something that should not fall on it. Its sole goal should be to increment a shared value in a consistent way with parallel execution. You should redirect that printing logic within yourThread
, since, as you can see, their code basically consists in making a single call.Breaking down your code
In your code, both threads manage to print the right number only at the start (the
System.out.println
without any text) because:SharedObject
's monitor, let's sayOddThread
, which means thatEvenThread
awaits the lock release in order to enter the synchronized block. At this point,OddThread
prints its corresponding number (1):OddThread
increments the value to 2, prints the notify statement, and finally notifies the other thread. Bear in mind that while the thread is doing all of this, it's still owning theSharedObject
's monitor.while
condition is tested. The followingif
fails, as the number is now even,OddThread
releases the lock and waits until is notified byEvenThread
.EvenThread
can finally enter the synchronized statement and prints its value (2).EvenThread
increments the value to 3, prints the notify statement with value 3 (so it's printing twice and also the wrong number), and finally notifies the other thread.EvenThread
tests thewhile
condition, fails theif
statement, prints the waiting statement, and then awaits forOddThread
to awake it.wait()
invocation. Both of them resume when the number is their right "type", increment the value (making it their opposing type), and then print the notify statement. This, not only explains why each thread prints their opposing number type, but it also explains why they keep printing even after the max value of 10 is reached. They both increment one more time after reaching the lastwhile
iteration, since they both resume from their lastwait()
call.Solution
Here is an implementation addressing the issues listed above.