How Java thread maps to OS thread?

本文详细解析了Java线程如何映射至操作系统线程,包括JVM内部处理流程、JNI接口作用及Linux环境下pthreads的使用。通过实例代码展示了线程创建与管理的全过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Java 线程是如何映射到操作系统线程中的呢?

 

 

Unmesh Joshi

Follow

Dec 30, 2017 · 3 min read

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?

Java虚拟机线程映射到操作系统线程是一个通常大家都熟知的说法。但是它真正的意义是什么呢?我们在Java环境中创建一个线程的对象,并且调用它的start()方法去启动一个新的线程。它是如何启动操作系统线程的呢?在线程对象中的run方法执行是如何依赖于操作系统线程的呢?

To explain what happens inside JVM, I have created a very small example at

https://github.com/unmeshjoshi/jvmthreads

Assume that we have to implement java.lang.Thread class ourselves. What we will need to do is as following.

我有一个非常小的例子去解释在java 虚拟机内部发生了什么,地址是:

https://github.com/unmeshjoshi/jvmthreads

假设我们必须自己实现Java.lang.thread类。我们需要做如下操作:

 

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.

它模拟了java的线程类,仅仅有两个方法,start()方法和run()方法。2️⃣去创建一个新的线程,我们只需要去创建一个线程对象然后调用它的start方法。

例子: new Thread().start()

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)

在调用被声明成原生方法的start()方法中发生了神奇的事情。这样本地的标记告诉JVM(java虚拟机),这是一个特定的平台的本地方法(用C语音或者C++语言编写的),需要通过Java本地的接口才能调用。JNI就是一个本地的方法接口规范,它详细的指出了本地代码是如何与JVM进行集成的,反之亦然。

 

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.

cd src/main/cpp

javah -classpath ../../../target/scala-2.12/classes -jni com.threading.Thread

The native method looks like following

 

JDK 有一个被叫做javah的工具,这个就是为本地方法生成一个头文件,然后就可以被用作本地实现。尝试如下命令。

 

cd src/main/cpp

javah -classpath ../../../target/scala-2.12/classes -jni com.threading.Thread

这个本地方法就像下边所示:

 

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.

第一个参数在这里的解释是JNI接口的指针。第二个对象jobject就是当本地方法被调用时候去处理的那个Java对象

在这个例子中它是这个线程对象的指针。

 

 

Native C/C++ implementation.

本地c/c++实现

We need to implement function Java_com_threading_Thread_start0. This is implemented in threading.cpp

我们需要实现函数Java_com_threading_Thread_start0。这个在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.

对于在Linux系统中创建线程,我们需要去使用pthreads接口。pthreads是POSIX标准的一部分,定义了C语言的接口去创建和管理线程。Linux系统提供了pthreads的实现。这个线程在被pthread_create函数所调用创建。

 

 

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.

tid是新创建的线程的ID。

attr是一个我们需要设置的线程属性集合

thread_entry_point是将被在新线程中调用的函数的指针

arg_to_entrypoint 是要传递给thread_entry_point的参数。

我们传递给pthread函数的输入点,那是线程对象的run方法将会被调用的地方。

从一个单独的Linux线程中访问线程Java对象,切入点的函数需要去访问JVM JNI对象,全局的JNI 引用到的Java线程对象。

我们通过创建一个名字是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

https://docs.oracle.com/javase/9/docs/specs/jni/design.html)

这个JavaThreadWrapper的构造函数访问JVM的引用,并且创建一个全局的Java线程对象的引用。

 JavaThreadWrapper::JavaThreadWrapper(JNIEnv *env, jobject javaThreadObjectRef) {
 env->GetJavaVM(&(this->jvm));
 this->threadObjectRef = env->NewGlobalRef(javaThreadObjectRef);
 }

Calling Java Thread object’s run method.

调用Java线程对象的run方法

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

在一个单独的线程中去调用这个输入点的函数时,就需要去调用Java线程对象中的run方法。

代码如下:

 

The run method is invoked through JNI as following

这个run方法通过JNI调用如下所示:

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.

jdk9/hotspot/src/share/vm/prims/jvm.cpp

jdk9/hotspot/src/share/vm/runtime/thread.cpp

jdk9/hotspot/src/os/linux/vm/os_linux.cpp

 

如你所见,我们明确的为每个Linux线程都创建了一个线程对象。JVM也是做了相似的某些操作。

参考一下jvm代码库中的一下源文件,你可以从http://hg.openjdk.java.net/jdk9/jdk9](http://hg.openjdk.java.net/jdk9/jdk9).中切出JVM 代码库。

创建和管理线程的代码在如下所列的文件中

Running sample code

运行示例代码。

Refer to https://github.com/unmeshjoshi/jvmthreads which has instructions to run the code.

请参阅https://github.com/unmeshjoshi/jvmthreads ,这里面包含了代码运行说明。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值