1

I have a small test using just two threads as follows:

import static java.lang.System.out;


@Test
public void testTwoSimpleThreads() {
    doInParallelAsync(() -> {
                out.println("First Ok");
            },
            () -> {
                out.println("Second Ok");
            });
}

private void doInParallelAsync(Runnable first, Runnable second) {
    new Thread(() -> {
        first.run();
    }).start();

    new Thread(() -> {
        second.run();
    }).start();
}

Sometimes the output will only include one of them before I introduced join() after they're started.

Two different outputs I encountered so far:

one

First Ok

Two

First Ok
Second Ok

I know the println() is synchronized and also I know the threads created by main thread are user threads in default and user threads will not exit until they finish.

Though I am using @Test, I tested it that they're non-daemon as expected.

non-daemon

is a daemon thread if and only if the creating thread is a daemon

And

The Java Virtual Machine continues to execute threads until either of the following occurs:

  1. The exit method of class Runtime has been called and the security manager has permitted the exit operation to take place.

  2. All threads that are not daemon threads have died, either by returning from the call to the run method or by throwing an exception that propagates beyond the run method.

UPDATED

Actually I know what the answers point out, I wonder why the output disappear?

Questions I need to ask:

  1. The pipeline closed by the main thread?

  2. Why? Is it because each pipeline is bond to one thread independently? Not shared? (that the pipeline won't be closed until the last thread finish just like the reference counting - the file will not be deleted until no one is using it)

  3. The last question: is it controlled by JVM or dependent upon the OS?

It seems the pipeline is closed by the @Test I mentioned. Thank you, @meriton for pointing it out.

Conclusion

When I tried this method in an ordinary main(), and directly invoke System.exit(0); just right after the start(), the output is quite the same as that when using @Test.

When using @Test (Junit), the threads will not be waited. For more details, please check JUnit test not executing all threads created within the test and JUnit terminates child threads.

And here is an explanation from @Alex Lockwood which I personally prefer:

JUnit is a unit testing framework... as with the Android framework, it has a main thread from which it will call user-defined unit test methods. When a unit test returns, JUnit immediately invokes the next unit test method (or exits completely if there are no more unit test methods to call). JUnit doesn't know anything about the background threads you create/start, so you can't assume that it will sit around and wait for them to finish.

Community
  • 1
  • 1
Hearen
  • 7,420
  • 4
  • 53
  • 63
  • *output will only include one* Always the first **or** sometimes the second? – Scary Wombat Jun 27 '18 at 01:25
  • 1
    You're not showing what `out` is or how you create it. Please add that. – Erwin Bolwidt Jun 27 '18 at 01:31
  • @ScaryWombat I just updated my question, would you please take a look? Thank you ~ – Hearen Jun 27 '18 at 01:40
  • @ErwinBolwidt Thanks for the reminder, just updated the question. – Hearen Jun 27 '18 at 01:40
  • @Hearen I cant still see the out variable and how you initialized it ? – Aman Chhabra Jun 27 '18 at 01:42
  • Check this answer: https://stackoverflow.com/questions/9651842/will-main-thread-exit-before-child-threads-complete-execution – Pavel Molchanov Jun 27 '18 at 01:44
  • @PavelMolchanov I know the difference between **daemon** and **non-daemon** about termination. My question is why the **output** pipeline will be closed. I updated my question, please check it for details. Thank you ~ – Hearen Jun 27 '18 at 01:46
  • @Hearen Why do you expect pipleline to remain open If there is nothing to be done by user thread? – Aman Chhabra Jun 27 '18 at 01:47
  • @AmanChhabra **Threads** created by **main** thread are all **user** threads in default. So? There are **user** threads still existing after **main** thread terminated. – Hearen Jun 27 '18 at 01:49
  • 1
    @Hearen Yes agreed, but as main thread has finished out will not work any more. For instance try the same thing on Jshell and you will always get both the output, but the second output sometimes go as another command, that is because main thread didn't wait for child threads to close and completed and hence jshell moved to next command line on which you can see the other output – Aman Chhabra Jun 27 '18 at 01:53
  • 1
    Please read and reply to the second top comment above. I am guessing that the `main` thread opens **and** implicitly `closes` the `out` – Scary Wombat Jun 27 '18 at 01:54
  • @ScaryWombat Sorry I misunderstood your point. It's a `System.out` actually. Just updated. Thank you ~ – Hearen Jun 27 '18 at 01:57
  • @Hearen Updated my answer, hopefully that will give you a better understanding about it. – Aman Chhabra Jun 27 '18 at 01:58
  • You are correct in assuming that *if at least one user thread is alive, the Java runtime won't terminate your application.* but in you example you can not even be sure that `Thread2` has even started – Scary Wombat Jun 27 '18 at 02:23

2 Answers2

2

Thats because you started them on a different thread and the main thread do not wait for child threads to complete and will close its execution immediately after last line.

So, by that time if Thread 1 is executed Output will be:

First Ok

If Thread 2 is executed:

Second Ok

And if by luck both got executed then

First Ok 
Second Ok

or

Second Ok 
First Ok

By providing join, you are asking main thread to wait for the child thread to be completed and hence both the outputs.

-- EDITED --

This doesn't mean that the child threads were terminated, they still completed their execution but you may not be able to see the results as outstream may have been closed or released by that time

If you execute the same command on Jshell, you will always get the second output, but sometimes it come in as another command, because as soon as main thread completes, Jshell moves to next command line:

enter image description here

Aman Chhabra
  • 3,824
  • 1
  • 23
  • 39
  • Thanks for the reply, but it actually doesn't solve my problem. – Hearen Jun 27 '18 at 01:38
  • 1
    @Hearen why not? You need to wait for each Thread to terminate before terminating the `main` thread. You can do this by using `join` or a countdownLatch – Scary Wombat Jun 27 '18 at 01:43
  • @ScaryWombat I updated my question. Would you please check it? The termination time is understood but my confusion lies not here. – Hearen Jun 27 '18 at 01:47
  • @Hearen I think you need to rephrase your question, if you are asking something different, because for now, it seems that you are asking why the output was not shown for both the threads and I have already shared the reason for the same – Aman Chhabra Jun 27 '18 at 01:49
  • @AmanChhabra Thanks for the digging. Sorry to say this: still not answering my updated questions. Thank you, Aman. – Hearen Jun 27 '18 at 02:03
2

Might the test runner invoke System.exit() after all tests have run? Can you reproduce the partial output if you convert the test into an ordinary main() method?

(I'd try myself, but was unable to reproduce a partial output when running this as a JUnit test in eclipse)

... and no, System.out is a static field, and hence shared by all threads. Exiting the main thread does not close the stream.

meriton
  • 68,356
  • 14
  • 108
  • 175
  • Thank you so much, meriton. I just cannot **re-produced** that *in-complete* output any more in plain main program. It seems it's the **runner** close it. – Hearen Jun 27 '18 at 02:32