Home > Software engineering >  No atomicity with Thread.join()
No atomicity with Thread.join()

Time:07-02

Consider the following code:

Thread t1 = new Thread(() -> {
  System.out.println("t1 running");
  System.err.println("foo 1");
});
Thread t2 = new Thread(() -> {
  System.out.println("t2 running");
  System.out.println("foo 2");
});
Thread t3 = new Thread(() -> {
  System.out.println("t3 running");
  System.out.println("foo 3");
});

t1.start();
t1.join();
t2.start();
t2.join();
t3.start();
t3.join();

All of the threads above is supposed to execute sequentially since I'm not starting them all at once and I do call Thread.join() on each of them to block the main thread from executing until each has been executed. I'd expect the following atomic output:

t1 running
foo 1
t2 running
foo 2
t3 running
foo 3

But this is the actual result, which does kind of confuse me:

t1 running
t2 running
foo 2
t3 running
foo 3
foo 1

As far as I'm concerned the only possible reason for that would be if there was another thread created for System.err under the hood printing "foo 1". Please do enlighten me on what is the real cause for such behaviour.

CodePudding user response:

of course the code executes sequentially, you can check this(not by checking logs order in different streams!):

    AtomicInteger counter = new AtomicInteger(0);
    Thread t1 = new Thread(() -> {
        System.out.println("t1 running ["   counter.incrementAndGet()   "]");
        System.err.println("foo 1 ["  counter.incrementAndGet()  "]");
    });
    Thread t2 = new Thread(() -> {
        System.out.println("t2 running ["  counter.incrementAndGet()  "]");
        System.out.println("foo 2 ["   counter.incrementAndGet()  "]");
    });
    Thread t3 = new Thread(() -> {
        System.out.println("t3 running ["   counter.incrementAndGet()  "]");
        System.out.println("foo 3 ["   counter.incrementAndGet() "]");
    });

    t1.start();
    t1.join();
    t2.start();
    t2.join();
    t3.start();
    t3.join();

output:

t1 running [1]
t2 running [3]
foo 2 [4]
t3 running [5]
foo 3 [6]
foo 1 [2]

note that the out and err streams can being flushed differently (in my case I see the correct expected order when I run this code in terminal, but I see the incorrect order when I run in IntelliJ, see this)

  • Related