我们知道,new一个thread,调用它的start的方法,就可以创建一个线程,并且启动该线程,然后执行该线程需要执行的业务逻辑,那么run方法是怎么被执行的呢?
Java线程和os线程 os线程我们知道,java的一个线程实际上是对应了操作系统的一个线程;
而操作系统实现线程有三种方式:
内核线程实现
用户线程实现
用户线程加轻量级进程混合实现
具体详细实现方式就不具体讲了,参见 «深入理解 JAVA虚拟机»第二版 第12章 Java内存模型与线程(378页)
Java线程Java线程在JDK1.2之前,是基于用户线程实现的。而在JDK1.2中,线程模型替换为基于操作系统原生线程模型来实现。
而在目前的JDK版本中,操作系统支持怎样的线程模型,在很大程度上决定了Java虚拟机的线程是怎样映射的,这点在不同的平台上没法达成一致。
对于Sun JDK来说,它的Windows版本和Linux版本都是使用一对一的线程模型实现的,一条Java线程映射到一条轻量级进程之中。
以上按个人理解摘自: «深入理解 JAVA虚拟机»第二版
Java线程创建 创建方式Desc:我们看到,无论以哪种方式创建,最终我们都会重写一个叫做 run 的方法,来处理我们的业务逻辑,然而我们都是调用一个start方法,来启动一个线程;
那 start方法和run方法之间是一个什么关系呢?从后边的介绍我们将获得这样一个信息:run就是一个回调函数,和我们普通的函数没有区别。
Java线程的实现一个 Java 线程的创建本质上就对应了一个本地线程(native thread)的创建,两者是一一对应的。
关键问题是:本地线程执行的应该是本地代码,而 Java 线程提供的线程函数(run)是 Java 方法,编译出的是 Java 字节码,
所以, Java 线程其实提供了一个统一的线程函数,该线程函数通过 Java 虚拟机调用 Java 线程方法 , 这是通过 Java 本地方法调用来实现的。
以下是 Thread#start 方法的示例:
可以看到它实际上调用了本地方法 start0, 而start0声明如下:
private native void start0();
也就是新创建的线程启动调用native start0方法,而这些native方法的注册是在Thread对象初始化的时候完成的,look:
Thread 类有个 registerNatives 本地方法,该方法主要的作用就是注册一些本地方法供 Thread 类使用,如 start0(),stop0() 等等,可以说,所有操作本地线程的本地方法都是由它注册的。
这个方法放在一个 static 语句块中,当该类被加载到 JVM 中的时候,它就会被调用,进而注册相应的本地方法。
而本地方法 registerNatives 是定义在 Thread.c 文件中的。Thread.c 是个很小的文件,它定义了各个操作系统平台都要用到的关于线程的公用数据和操作,如下:
1 JNIEXPORT void JNICALL 2 Java_Java_lang_Thread_registerNatives (JNIEnv *env, jclass cls){ //registerNatives 3 (*env)->RegisterNatives(env, cls, methods, ARRAY_LENGTH(methods)); 4 } 5 static JNINativeMethod methods[] = { 6 {"start0", "()V",(void *)&JVM_StartThread}, //start0 方法 7 {"stop0", "(" OBJ ")V", (void *)&JVM_StopThread}, 8 {"isAlive","()Z",(void *)&JVM_IsThreadAlive}, 9 {"suspend0","()V",(void *)&JVM_SuspendThread}, 10 {"resume0","()V",(void *)&JVM_ResumeThread}, 11 {"setPriority0","(I)V",(void *)&JVM_SetThreadPriority}, 12 {"yield", "()V",(void *)&JVM_Yield}, 13 {"sleep","(J)V",(void *)&JVM_Sleep}, 14 {"currentThread","()" THD,(void *)&JVM_CurrentThread}, 15 {"countStackFrames","()I",(void *)&JVM_CountStackFrames}, 16 {"interrupt0","()V",(void *)&JVM_Interrupt}, 17 {"isInterrupted","(Z)Z",(void *)&JVM_IsInterrupted}, 18 {"holdsLock","(" OBJ ")Z",(void *)&JVM_HoldsLock}, 19 {"getThreads","()[" THD,(void *)&JVM_GetAllThreads}, 20 {"dumpThreads","([" THD ")[[" STE, (void *)&JVM_DumpThreads}, 21 };
观察上边一小段代码,可以容易的看出 Java 线程调用 start->start0 的方法,实际上会调用到 JVM_StartThread 方法,那这个方法又是怎么处理的呢?
实际上,我们需要看到的是该方法最终要调用 Java 线程的 run 方法,事实的确也是这样的。
在 jvm.cpp 中,有如��代码段:
JVM_ENTRY(void, JVM_StartThread(JNIEnv* env, jobject jthread)){ ... native_thread = new JavaThread(&thread_entry, sz); ... }