Skip to content
Advertisement

What happens at runtime when we have multiple Java threads?

I am trying to understand what happens when you have multiple thread objects and you call start on them.

To this end, I have written the following code:

public class Testing {
    public static void main(String[] args) {
        for(int i =0; i <100; i++){
            (new TestThread()).start();
        }
    }
}

class TestThread extends Thread {
    @Override
    public void run() {
        System.out.println("Thread instance: " + Thread.currentThread().getName());
    }
}

So the output I get involves Thread-x, where x is from 0 to 99, but they are in different order than the natural order (i.e. 0,1,2,3,…). I expected this because I read that we have no control over what happens when these threads run, but I wanted to ask for clarification on exactly what happens during runtime.

Is it the case that the main thread goes through all 100 iterations of the for loop creating these threads, and then the JVM arbitrarily decides later when each of these Thread objects starts?

Thanks.

Advertisement

Answer

I wanted to ask for clarification on exactly what happens during runtime.

What actually happens is that when you call start(), the JVM typically1 makes syscalls to the operating system to do the following:

  1. Allocate memory segments for the new thread stack. (Typically two segments are allocated: one segment for the thread stack, and a second read-only segment that is used to detect stack overflow.)

  2. Create a new native thread2.

When the native thread is created, it must wait (along with all of the other currently ready-to-run threads) for the OS’s thread scheduler to schedule it to a physical core. Generally speaking the OS’s thread scheduler respects priorities, but scheduling between threads of the same priority is typically not “fair”; i.e. it is not guaranteed to be “first come, first served”.

So, at some point, the OS will schedule the new native thread to run. When that occurs, the thread will execute some native code that gets hold of the Runnable reference and call its run() method. The same code will deal with any uncaught exceptions from the run() method.

The precise details will be JVM specific and OS specific, and you don’t really need to know to them.


Is it the case that the main thread goes through all 100 iterations of the for loop creating these threads, and then the JVM arbitrarily decides later when each of these Thread objects starts?

Not necessarily. It might do, or it might not.

What actually happens will depend on how the OS’s native code scheduler deals with a newly created native thread. And that will depend on various factors which are difficult to predict. For example, the behavior of other threads, and other applications, and so on.

Basically, there are no guarantees3 that the child threads will start executing in any particular order, or that the main thread will or won’t complete the loop before any of the child threads starts.


1 – This is typical for a JVM which provides a 1 to 1 mapping between Java threads and native threads. This is the way that most current generation JVMs behave, but it is not the only implementation model.
2 – A native thread is a thread supported by the operating system. See Java Threading Models for more information and Native POSIX Thread Library for an example.
3 – Under some platforms and load conditions, you may be able to observe patterns of behavior, but you are liable to find that the behavior is different on other platforms, etc.

User contributions licensed under: CC BY-SA
5 People found this is helpful
Advertisement