Felix
Felix

Reputation: 139

Can't print all numbers from thread that iterates over natural numbers

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();
            }
        }
    }
}

When you start the program the following will be printed in the console:

1,3,4,5,6

Why does the number 2 get skipped? I do not think that it is a timing issue. Any ideas?

Upvotes: 2

Views: 77

Answers (3)

Ansorre
Ansorre

Reputation: 81

Two reasons:

  1. because the static int i variable is used by two different threads simultaneously causing unpredictable behaviors due to race condition. This problem is solved replacing static int i with static AtomicInteger i
  2. System.nanoTime() - timer > 1E9 / 60 will not execute the code in the while loop at exactly predictable times.

Upvotes: 1

Andrew
Andrew

Reputation: 49606

The output 1,3,4,5,6 doesn't seem to be constant. It may vary due to improper synchronisation.

The reader prints the value when it obtains it. It doesn't care whether the value has been updated or how many times this value has been updated.

The writer changes the value independently of the reader. It doesn't care about the last value the reader has read.


There is a common problem in multithreading called the readers-writers problem. You reproduced the simplest kind of this issue: one reader to one writer.


You ran identical pieces of code in parallel probably assuming they could some kind "overlay" each other as follows:

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

Unfortunately, it never works that way.

There is no "happened-before" relation, therefore there is no guarantee the "increment-then-print" or "print-then-increment" patterns will always work.

Upvotes: 2

assylias
assylias

Reputation: 328598

Without any synchronisation, this is an example of valid execution (Thread 1 is the thread you create, Thread 2 is the main thread):

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

Note that another valid execution, for example, would be to repeatedly print 1.

Upvotes: 2

Related Questions