How Java thread maps to OS thread?
JVM thread maps to OS thread is a commonly read statement. But what does it really mean?. We create Thread object in java and call its start method to start new thread. How does it start OS thread? and how the run method of the Thread object is attached to the OS thread that is executed?
To explain what happens inside JVM, I have created a very small example at
Assume that we have to implement java.lang.Thread class ourselves. What we will need to do is as following.
The Thread class.
Its simulates Java’s Thread class. It has only two methods, start() and run(). To create a new Thread, we just need to create a new Thread object and call its start method.
The magic happens inside the start method, which invokes a start0 method which is declared as a native method. The ‘native’ marker tells JVM that this is a platform specific native method (written in C/C++) which needs to be invoked through java native interface. JNI is a native method interface specification for Java and it details out how native code can integrate with the JVM and vice versa. (https://docs.oracle.com/javase/9/docs/specs/jni/design.html#jni-interface-functions-and-pointers)
Generating a header file for native method declaration.
JDK has a tool called javah which generates a header file for classes declaring native method, which then can be used for native implementation. Try following commands
A header file for Thread class can be generated as follows.
javah -classpath ../../../target/scala-2.12/classes -jni com.threading.Thread
The native method looks like following
The first argument is the JNI interface pointer as explained here. The second object jobject is handle to the Java object on which the native method is called. In this case it’s pointer to the Thread object.
Native C/C++ implementation.
We need to implement function Java_com_threading_Thread_start0. This is implemented in threading.cpp
Creating linux thread with pthreads.
For creating threads on linux, we need to use pthread interface. Pthread is part of POSIX standard which defines C language interface for creating and managing threads. Linux provides implementation of pthreads. The thread is created by calling pthread_create function.
tid is the ID of the newly created thread.
attr is set of thread attributes we need to set
thread_entry_point is pointer to function which will be called from new thread
arg_to_entrypoint is the argument to be passed to thread_entry_point
The entry point function we pass to pthread is where we should be invoking Thread object’s run method.
For accessing Thread java object from a separate linux thread, the entry point function needs to have access to JVM JNI object and global JNI reference to Java Thread object.
We do that by creating a wrapper object called JavaThreadWrapper.
The constructor of JavaThreadWrapper gets access to JVM reference and creates a global reference to java thread object.
(To know more on local vs global references have a look at
Calling Java Thread object’s run method.
The entry point function when invoked in a separate thread now need to invoke java Thread object’s run method.
The code looks like following
The run method is invoked through JNI as following
As you can see, we literally created a linux thread for every thread object created. JVM does something exactly similar.
For reference have a look at following source files in the JVM codebase. You can checkout JVM codebase from http://hg.openjdk.java.net/jdk9/jdk9.
The code for creating and managing threads is in following files.
Running sample code
Refer to https://github.com/unmeshjoshi/jvmthreads which has instructions to run the code.