0

Below is my sample code, when my a.start() called it should create a thread and print "Run" immediately. But why does is called after printing "begin" 20 times.

How does thread "a" decide that it doesn't have to call run() immediately.

public class JoinTest implements Runnable {

    public static void main(String[] args) throws InterruptedException {
        Thread a = new Thread(new JoinTest());
        a.start();

        for (int i = 0; i < 20; i++) {
            System.out.print("Begin");
        }
        Thread.sleep(1000);

        a.join();
        System.out.print("\nEnd");
    }

    public void run() {
        System.out.print("\nRun");
    }
}

Output:

BeginBeginBeginBeginBeginBeginBeginBeginBeginBeginBeginBeginBeginBeginBeginBeginBeginBeginBeginBegin
Run
End

I am little confused about the behavior of thread.

In my opinion "run" should be printed before "begin" because it get printed before the join() method is called, and at the time of join method called thread "a" must have finished its execution and calling join must be useless at that point.

Uma Kanth
  • 5,659
  • 2
  • 20
  • 41
RaT
  • 1,134
  • 3
  • 12
  • 28
  • 1
    `In my opinion "run" should be printed before "begin"...` No, there's no such requirement. All that is guaranteed is that "Run" will be printed before "End", because of `join()`. – biziclop Jul 30 '15 at 09:32
  • A thread doesn't decide when it is run. That's entirely down to the Operating System's scheduler. – Phylogenesis Jul 30 '15 at 09:36
  • I have tried many scenarios with join(), "run" always get printed after "begin" but when i remove the join statement "run" always get printed before "begin". Why? – RaT Jul 30 '15 at 09:46

4 Answers4

2

You start the thread, then immediately do some printing, then sleep. Looking at your code I would actually expect to see Begin before Run because the thread is being started in the background, concurrently to your main thread going on with its work. Futhermore, the print method is synchronized so you repeatedly acquire that lock in a loop, giving even less chance to the second thread to interject.

I have tried your code with Thread.sleep eliminated, both with and without the join call. The behavior is the same in both cases: Run comes at the end most of the time and occasionally manages to get interleaved between the Begin words. Everything exactly as expected by the simple model of concurrency with synchronized blocks.

Here is a slight variation on your code which reliably prints Run before everything else, whether you call the join method or not. All that changed is the position of the sleep call.

public class JoinTest implements Runnable
{
  public static void main(String[] args) throws InterruptedException {
    Thread a = new Thread(new JoinTest());
    a.start();

    Thread.sleep(1000);
    for (int i = 0; i < 20; i++) {
      System.out.print("Begin");
    }

    a.join();
    System.out.print("\nEnd");
  }

  public void run() {
    System.out.print("\nRun");
  }
}
Marko Topolnik
  • 195,646
  • 29
  • 319
  • 436
2

Calling start() on a thread doesn't necessarily triggers the execution of its run() method immediately. Your thread is marked as started but the main thread pursues its execution into the for loop. Then the JVM is switching to your thread once the main thread reaches the sleep() statement.

dotvav
  • 2,808
  • 15
  • 31
  • when I remove the `Thread.sleep(1000)` statement it gives again the same output. – RaT Jul 30 '15 at 09:40
  • Anyways... your second thread is marked as started but it is not run immediately. – dotvav Jul 30 '15 at 09:42
  • but when i remove the a.join() statement it gives the immediate effect and "run" get printed before "begin" – RaT Jul 30 '15 at 09:50
0

The start() method calls the thread's run() method, although this takes a little time, which may just be enough for some or all of your 'Begin' loops to complete. When I run this on my machine the 'Run' output appears between the first and second 'Begin'. Try outputting with timestamps so you can see how long your machine is taking to execute each command:

public class JoinTest implements Runnable {

    public static void main(String[] args) throws InterruptedException {
        Thread a = new Thread(new JoinTest());
        a.start();

        for (int i = 0; i < 20; i++) {
            System.out.println("Begin " + System.nanoTime());
        }
        Thread.sleep(1000);

        a.join();
        System.out.println("End " + System.nanoTime());
    }

    public void run() {
        System.out.println("Run " + System.nanoTime());
    }
}

Calling a.join() at that point ensures that you will always see 'Run' output before 'End', as join() waits for the thread to complete.

Kieran
  • 343
  • 2
  • 10
0

I have tried many scenarios with join(), "run" always get printed after "begin" but when i remove the join statement "run" always get printed before "begin". Why?

Because it's allowed. That's why. As soon as you call .start(), you have two threads. Untill your program calls a synchronization methods like .join() it's entirely up to the JVM implementation and the operating system to decide which thread gets to run when.

The a.join() call from your main thread forces the main thread to wait until the a thread has completed its run() method.

Without the a.join() call, the Java Language Specification permits the a thread to complete its work before a.start() returns in the main thread, and it permits the main thread to reach the end of the main() function before the a thread even begins to run, and it permits anything in between to happen.

It's entirely up to the JVM and the OS.

If you want to take control of the order in which things happen, then you have to use synchronized blocks, and synchronization objects and method (e.g., .join()).

But beware! The more you force things to happen in any particular order, the less benefit your program will get from using threads. It's best to design your program so that the threads can function independently of one another most of the time.

Solomon Slow
  • 25,130
  • 5
  • 37
  • 57