【发布时间】:2016-08-13 20:19:41
【问题描述】:
这是一个面试问题,我认为它与现实生活中的实际问题没有任何关系。
我必须按顺序打印数字 12345.... 但条件是我必须使用两个线程打印它,一个负责打印奇数,一个负责打印偶数。
到目前为止,我已经想出了这个解决方案。
package junk.concurrency;
public class PrintEvenOddTester {
public static void main(String... args) {
TaskEvenOdd t = new TaskEvenOdd(10);
Thread t1 = new Thread(t, "odd printer");
Thread t2 = new Thread(t, "even printer");
t1.start();
t2.start();
}
}
class TaskEvenOdd implements Runnable {
private int max;
private boolean isOdd = true;
private int number = 1;
TaskEvenOdd(int max) {
this.max = max;
}
synchronized void printEven(int number) { // sync on runnable itself
while (isOdd) { // if odd is to be printed, wait
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("Even:" + this.number); // LINE-1
isOdd = true;
this.number++; // LINE-2
notifyAll();
}
synchronized void printOdd(int number) { // sync on runnable itself
while (!isOdd) { // if even is to be printed, wait
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("Odd:" + this.number); // LINE-3
this.number++; // LINE-4
isOdd = false;
notifyAll();
}
@Override
public void run() {
while (number <= max) {
if (Thread.currentThread().getName().equals("even printer")) {
printEven(number);
} else {
printOdd(number);
}
}
}
}
1
在编写此代码时,我观察到一种我不理解的奇怪行为。如果在上面代码的第 1、2、3、4 行,我写 number 而不是 this.number 我的 number 实例变量没有增加,代码只打印无限数量的 1。
我假设printEven 和printOdd 方法都是在可运行实例本身上调用的,那么为什么它的值没有增加。我尝试使number volatile,但仍然产生相同的输出。
2
我还看到数字打印到 11 点而不是 10 点。我理解为什么会发生这种情况(因为最后一次调用 printOdd 会通过最后一次调用 printEven(正在打印 10)得到通知,因此会打印 11 ),避免这种情况的一种方法是每次打印前检查数字,看看它是否在限制之下,但我想知道克服这个问题的最佳方法是什么。
谢谢。
EDIT 方法参数number 完全多余,可以省略。这个 if(this.max>=number) 条件可以在打印数字之前使用。
【问题讨论】:
-
如果我曾经在面试中问过这个问题,我想要的答案是,“这是一件非常愚蠢的事情。如果你想让任何程序以特定的顺序执行一系列事情,那么实现这一目标的正确方法是在一个线程中完成所有事情。”如果有人问我这个问题,然后说,“好的,但无论如何都要这样做”,我将创建一个通用解决方案,其中任意数量的线程轮流通过将令牌从一个传递给other through
BlockingQueues:当一个线程接收到令牌时,就轮到它了。完成后,它将令牌交给下一个线程。
标签: java multithreading concurrency