无法打印迭代自然数的线程中的所有数字

时间:2018-03-07 14:24:44

标签: java multithreading

public class Test {

    static int i = 1;

    public static void main(String[] args) {

        new Thread(() -> {

            long timer = System.nanoTime();

            while (true) {

                while (System.nanoTime() - timer > 1E9 / 60) {

                    i++;
                    timer = System.nanoTime();
                }
            }
        }).start();

        long timer = System.nanoTime();

        while (true) {

            while (System.nanoTime() - timer > 1E9 / 60) {

                System.out.println(i);
                timer = System.nanoTime();
            }
        }
    }
}

启动程序时,控制台中将打印以下内容:

1,3,4,5,6

为什么跳过号码2?我不认为这是一个时间问题。有什么想法吗?

3 个答案:

答案 0 :(得分:1)

没有任何同步,这是有效执行的示例(线程1是您创建的线程,线程2是主线程):

Thread 1     Thread 2
i = 2
             print i: 2
i = 3
             print i: 3
             print i: 3  //loop iterates twice in Thread 2
i = 4
i = 5                    //loop iterates twice in Thread 1
             print i: 5
i = 6
             print i: 5 //main thread doesn't see the update
i = 7
             print i: 5 //main thread doesn't see the update

请注意,例如,另一个有效的执行是重复打印1。

答案 1 :(得分:1)

输出1,3,4,5,6似乎不变。它可能因同步不当而有所不同。

阅读器在获取值时打印该值。它并不关心值是否已更新或此值已更新的次数。

作者独立于读者更改值。它并不关心读者阅读的最后一个值。

多线程中存在一个称为the readers-writers problem的常见问题。您重现了这个问题中最简单的问题:一位读者与一位作家

你并行运行相同的代码片段,可能假设它们可以某种类型" overlay"彼此如下:

while (true) {
    while (System.nanoTime() - timer > 1E9 / 60) {
        i++;
        System.out.println(i);
        timer = System.nanoTime();
    }
}

不幸的是,它永远不会这样。

没有"happened-before"关系,因此无法保证" increment-then-print" " print-then-增量" 模式将始终有效。

答案 2 :(得分:0)

有两个原因:

  1. 因为static int i变量由两个不同的线程使用 同时由于种族而导致不可预测的行为 条件。用{替换static int i解决了这个问题 static AtomicInteger i
  2. System.nanoTime() - timer > 1E9 / 60     不会在完全可预测的情况下执行while循环中的代码     次。