Home > Back-end >  Java threading - How to properly wait for threads to finish?
Java threading - How to properly wait for threads to finish?

Time:11-12

I had a test at university telling me to fix the code below, so it waits for the threads to finish before printing "END". content of MyThread was unknown:

Thread s1 = new MyThread();
Thread s2 = new MyThread();
s1.start();
s2.start();
s1.sleep(1000);
s2.sleep(1000);
System.out.println("END");

My solution at first was to join() the 2 threads, however that did not work.

Thread s1 = new MyThread();
Thread s2 = new MyThread();
s1.start();
s2.start();
s1.sleep(1000);
s2.sleep(1000);
s1.join();
s2.join();
System.out.println("END");

Then I tried checking if the Threads were alive with a while loop.

Thread s1 = new MyThread();
Thread s2 = new MyThread();
s1.start();
s2.start();
s1.sleep(1000);
s2.sleep(1000);
while(s1.IsAlive() || s2.IsAlive){
  continue;
}
System.out.println("END");

But this one did not work either. Apperantly the correct answer was to join the threads AND remove the 2 sleeps:

Thread s1 = new MyThread();
Thread s2 = new MyThread();
s1.start();
s2.start();
s1.join();
s2.join();
System.out.println("END");

My question is: Why are none of my answers acceptable? Asked my lab leader, but he could not give me an answer. Coded the test out at home and it seems to work just fine. Thanks in advance for the help!

CodePudding user response:

Imagine a future scenario: you now work in a bank or worse yet a nuclear power station. The importance of knowing precisely when those background tasks are completed is much higher.

The solutions that use sleep(x) may appear to work if the task is short lived, but a sleep gives no guarantee that the operations were completed. What if each MyThread takes 1 millisecond and your code is called a million times? Using sleep(1000) means that your program will run for an excessively long time without knowing the transactions definitely ended.

The solution with while(s1.IsAlive()... may appear to work but is a fail because your calling thread is running a tight loop. It will be consuming excessive CPU because it is always running while others task are, and therefore that is at the detriment of the CPU allocated for MyThread tasks.

The correct answer uses Thread.join. Your calling thread blocks - no CPU wasted - until each MyThread ends. The elapsed time is exactly matched to their running time, and you know the MyThreads were ended.

CodePudding user response:

The solution with join() is for sure correct. If we look at the official docs we can see the following ...

public final void join​(long millis) throws InterruptedException Waits at most millis milliseconds for this thread to die. A timeout of 0 means to wait forever. This implementation uses a loop of this.wait calls conditioned on this.isAlive. As a thread terminates the this.notifyAll method is invoked. It is recommended that applications not use wait, notify, or notifyAll on Thread instance

This method was designed precisely to handle this use case.

The reason why you might not be getting the expected results is because of the t.sleep() calls you call on a reference to another thread, see one of the comments to the original post.

  • Related