【问题标题】:Print numbers sequentially using two threads使用两个线程顺序打印数字
【发布时间】: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。
我假设printEvenprintOdd 方法都是在可运行实例本身上调用的,那么为什么它的值没有增加。我尝试使number volatile,但仍然产生相同的输出。
2
我还看到数字打印到 11 点而不是 10 点。我理解为什么会发生这种情况(因为最后一次调用 printOdd 会通过最后一次调用 printEven(正在打印 10)得到通知,因此会打印 11 ),避免这种情况的一种方法是每次打印前检查数字,看看它是否在限制之下,但我想知道克服这个问题的最佳方法是什么。
谢谢。


EDIT 方法参数number 完全多余,可以省略。这个 if(this.max>=number) 条件可以在打印数字之前使用。

【问题讨论】:

  • 如果我曾经在面试中问过这个问题,我想要的答案是,“这是一件非常愚蠢的事情。如果你想让任何程序以特定的顺序执行一系列事情,那么实现这一目标的正确方法是在一个线程中完成所有事情。”如果有人我这个问题,然后说,“好的,但无论如何都要这样做”,我将创建一个通用解决方案,其中任意数量的线程轮流通过将令牌从一个传递给other through BlockingQueues :当一个线程接收到令牌时,就轮到它了。完成后,它将令牌交给下一个线程。

标签: java multithreading concurrency


【解决方案1】:

1

您的问题是您的方法的参数也称为 number 。所以它是遮蔽你班级的领域!所以,当你省略时,你增加了参数;这根本没有任何实际效果!

这个问题有两种解决方案:

a) 简单地避免这样做(因此,按照惯例,避免使用与参数和字段相同的名称)。

b) 使用能够发现此类问题并告知您的工具。例如,findbugs 有明确的rule 来告诉您有关阴影的信息。并且可能也可以告诉 IDE 对此发出警告。见here

2

考虑到这只是一个“简单”的任务......在我看来,简单检查整个班级的“限制”就可以了。

【讨论】:

  • 我想知道我怎么没有观察到这么小的东西。谢谢你指出这一点。您能否对问题的第二部分发表评论。
  • “使用工具来发现此类问题并告诉您”您能否详细说明这一点。另外,如果 case-2 有其他解决方案,请告诉我。
  • 添加了此类工具的示例。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-09
  • 2018-01-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多