您的位置:创新中国网 > 科技

从Java到C++,以JVM的角度看Java线程的创建与运行

发布时间:2017年10月18日 14:01 来源:geceo.com 编辑:创新中国   阅读量:7735   
导读:线程的创建故事的开始,是这样的一段的代码:Threadthread=newThread(newRunnable()Overridepublicvoidrun()System.out.println(Thread.currentThread(...

线程的创建

故事的开始,是这样的一段的代码:

Thread thread = new Thread(new Runnable()

Override

public void run()

System.out.println(Thread.currentThread().getName());

);

thread.start();

然后我们的目标就是,在C++源码中找到这个run()方法是在哪里执行的。

首先进入的是它的构造方法:

public Thread(Runnable target) init(null, target, "Thread-" + nextThreadNum(), 0);

经过一系列的调用,最终跳到这个方法,(这里的代码有点长,就不给出完整代码,完整的源码在这里:源码传送门)

/**

* Initializes a Thread.

*

* param g 线程组

* param target 携带run方法的Runnable对象

* param name 线程名

* param stackSize 新线程的需要的stack size,若此值为0则表明此属性忽略

* param acc 将要被继承的AccessControlContext,若此值为null,则此属性默认设置为

* AccessController.getContext()

* param inheritThreadLocals 若此值为true,从构造此线程的线程中继承thread-locals的初始值

*/

private void init(ThreadGroup g, Runnable target, String name,

long stackSize, AccessControlContext acc,

boolean inheritThreadLocals)

if (name null)

throw new NullPointerException(“name cannot be null”);

this.name = name; Thread parent = currentThread(); SecurityManager security = System.getSecurityManager(); if (g null) /* Determine if it's an applet or not */ /* If there is a security manager, ask the security manager what to do. */ if (security != null) g = security.getThreadGroup(); /* If the security doesn't have a strong opinion of the matter use the parent thread group. */ if (g null) g = parent.getThreadGroup(); g.addUnstarted(); this.group = g; this.daemon = parent.isDaemon(); this.priority = parent.getPriority(); this.target = target; setPriority(priority); this.stackSize = stackSize; /* Set thread ID */ tid = nextThreadID();

稍微尝试着总结一下:

设置线程名(即设置name属性),一般情况下,这个name的格式是“Thread-X”,X是一个数字,代表用这个线程类初始化的第X个实例

设置线程的ThreadGroup,这个ThreadGroup要么从应用的SecurityManager处拿到,要么就直接继承父线程的ThreadGroup。(设置完成以后还会有一个验证)

在真正设置此线程的ThreadGroup之前,需要为这个ThreadGroup的“还未开始的线程数目”(nUnstartedThreads)加一

设置此线程是否为守护线程(即设置daemon属性),若父线程为守护线程,那么此线程也是守护线程

设置此线程的优先级(即priority属性)为父线程的优先级(顺便补充一句,子线程的优先级是不能大于父线程的)

设置此线程的上下文类加载器

设置这个Thread的target,这个target就是携带了我们写好的run()方法的Runnable对象

设置stackSize

设置线程ID(tid属性)

关于run方法的一个补充

或许有人会说,我创建线程的时候,是使用传递一个Runnable对象来进行创建对象,并没有重写原来的run方法,那么到了这里,还调用run方法的话,不就出问题了。

其实,这个问题我们看一下Thread.java的run()方法就好了:

Override

public void run()

if(target != null)

target.run();

target是什么,target就是我们在初始化Thread时传递进去的Runnable对象,那么这几行代码可以解释我们的几个疑问:

如果我们是通过传递Runnable对象来初始化Thread实例的话,那么就是将实例的run方法“替换”为Runnable对象的run()方法(逻辑上的替换)

如果我们的Thread继承类重写了run()方法,也就是说原本的“替换”逻辑被覆盖了,这时我们再通过传递Runnable对象来初始化Thread实例的话,这个实例的run不会再被替换,也就是这个实例仅会执行我们重写的run方法。

线程的开始

我们都知道,开始一个线程就是调用这个线程的start方法:

/** * 调用此方法将会使得thread开始运行,JVM会在这个线程中调用run方法。 * lt;pgt; * 调用结果是,两个线程同时运行:调用此线程的线程,以及此线程 * lt;pgt; * 无论在什么情况下,要求同一条线程开始两次都是不合法,即便是此线程已经结束在要求开始也是不合法的。 * * exception IllegalThreadStateException 若此线程曾经开始(start)过 * see #run() * see #stop() */ public synchronized void start() /** * * 对于main方法线程(即运行main方法的线程),或者是由虚拟机创建的“system”组的 * 线程,都不需要调用此方法来启动。 * 任何在这个方法中添加的新功能,以后都有可能添加到虚拟机上。 * 翻译的不是很满意,原文留在这里: * This method is not invoked for the main method thread or "system" * group threads created/set up by the VM. Any new functionality added * to this method in the future may have to also be added to the VM. * * 若线程的threadStatus为0,则表明这个状态是NEW状态 */ if (threadStatus != 0) throw new IllegalThreadStateException(); /* * 通知线程组:此线程已经就绪,可以开始运行了 * 所以,这条线程可以添加到线程组的线程list中,以及线程组 * 未开始线程的数目(he group's unstarted count)可以减一了。 * * */ group.add(this); boolean started = false; try start0(); started = true; finally try if (!started) group.threadStartFailed(this); catch (Throwable ignore) /* do nothing. If start0 threw a Throwable then it will be passed up the call stack */

挺简短的一段代码,我们可以总结出以下步骤:

第一步,非常重要,就是先检查线程的状态,如果线程的状态不是NEW状态的话,那么就会抛出一个异常(关于Java线程的状态,可以看这篇文章:Java 线程的几种状态)

第二步,将这个Thread添加到之前引用的ThreadGroup中

第三步,调用native start0()

关于Thread类中的native方法

在Thread.java里面,有一个registerNatives()的native方法,并且在Threa.java的第一个static块中就调用了这个方法,保证这个方法在类加载中是第一个被调用的方法。这个native方法的作用是为其他native方法注册到JVM中(可见:JVM查找java native方法的规则)。

通过这个方法,我们可以找到Thrad.java中native方法在JVM中对应方法:

Thread.c$Java_java_lang_Thread_registerNatives

static JNINativeMethod methods[] =

“start0”, “()V”, (void *)amp;JVM_StartThread,

“stop0”, “(” OBJ “)V”, (void *)amp;JVM_StopThread,

“isAlive”, “()Z”, (void *)amp;JVM_IsThreadAlive,

“suspend0”, “()V”, (void *)amp;JVM_SuspendThread,

“resume0”, “()V”, (void *)amp;JVM_ResumeThread,

“setPriority0”, “(I)V”, (void *)amp;JVM_SetThreadPriority,

“yield”, “()V”, (void *)amp;JVM_Yield,

“sleep”, “(J)V”, (void *)amp;JVM_Sleep,

“currentThread”, “()” THD, (void *)amp;JVM_CurrentThread,

“countStackFrames”, “()I”, (void *)amp;JVM_CountStackFrames,

“interrupt0”, “()V”, (void *)amp;JVM_Interrupt,

“isInterrupted”, “(Z)Z”, (void *)amp;JVM_IsInterrupted,

“holdsLock”, “(” OBJ “)Z”, (void *)amp;JVM_HoldsLock,

“getThreads”, “()[” THD, (void *)amp;JVM_GetAllThreads,

“dumpThreads”, “([” THD “)[[” STE, (void *)amp;JVM_DumpThreads,

;

JNIEXPORT void JNICALL

Java_java_lang_Thread_registerNatives(JNIEnv *env, jclass cls)

(*env)-gt;RegisterNatives(env, cls, methods, ARRAY_LENGTH(methods));

0、在进入C之前的准备

我们将会需要使用到这几个概念:

java.lang.Thread: 这个是Java语言里的线程类,由这个Java类创建的instance都会 1:1 映射到一个操作系统的osthread;

JavaThread: JVM中C++定义的类,一个JavaThread的instance代表了在JVM中的java.lang.Thread的instance, 它维护了线程的状态,并且维护一个指针指向java.lang.Thread创建的对象(oop)。它同时还维护了一个指针指向对应的OSThread,来获取底层操作系统创建的osthread的状态

OSThread: JVM中C++定义的类,代表了JVM中对底层操作系统的osthread的抽象,它维护着实际操作系统创建的线程句柄handle,可以获取底层osthread的状态

VMThread: JVM中C++定义的类,这个类和用户创建的线程无关,是JVM本身用来进行虚拟机操作的线程,比如GC

(引自:聊聊JVM(五)从JVM角度理解线程)

1、从Java进入C:JVM_StartThread

首先JVM会进入jvm.cpp的jvm.cpp$JVM_StartThread 方法(确切地说,这个JVM_StartThread是一个宏):

关于native的函数参数:

第一个参数:JNIEnv* 是定义任意native函数的第一个参数(包括调用JNI的RegisterNatives函数注册的函数),指向JVM函数表的指针,函数表中的每一个入口指向一个JNI函数,每个函数用于访问JVM中特定的数据结构。

第二个参数:调用java中native方法的实例或Class对象,如果这个native方法是实例方法,则该参数是jobject,如果是静态方法,则是jclass

接下来我们来看下这个JVM_StartThread方法:

JVM_ENTRY(void, JVM_StartThread(JNIEnv* env, jobject jthread))

JVMWrapper(“JVM_StartThread”);

JavaThread *native_thread = NULL;

bool throw_illegal_thread_state = false;

// We must release the Threads_lock before we can post a jvmti event

// in Thread::start.

//在我们操作的时候,确保C++线程和OSThread不会被提前释放 //(译者附:)从上面的一个左花括号开始,一直到下一个匹配的右花括号为止,都上了关于Threads_lock的互斥锁 //可以理解为Java的sync块 MutexLocker mu(Threads_lock); // 安全原因,先进行一次检测 if (java_lang_Thread::thread(JNIHandles::resolve_non_null(jthread)) != NULL) throw_illegal_thread_state = true; else // We could also check the stillborn flag to see if this thread was already stopped, but // for historical reasons we let the thread detect that itself when it starts running jlong size = java_lang_Thread::stackSize(JNIHandles::resolve_non_null(jthread)); // 为C++ thread结构体分配内存,以及创建一个本地线程。这个从Java取过来的stack size是有一个符号数, // 但构造器需要的size_t是一个无符号数,所以在转换的时候需要避免因为size是负数出现的问题。 size_t sz = size gt; 0 ? (size_t) size : 0; native_thread = new JavaThread(amp;thread_entry, sz); // 创建一个JavaThrea对象(创建过程见第二节),其中第二个参数thread_entry是一个方法指针,详见本节下方补充 // 仍做一次安全检测,因为osthread不一定能创建成功(详见下文第三节的osthread创建) if (native_thread-gt;osthread() != NULL) // 注意:当前线程在下面的“prepare”没有被使用到。 native_thread-gt;prepare(jthread);

if (throw_illegal_thread_state)

THROW(vmSymbols::java_lang_IllegalThreadStateException());

assert(native_thread != NULL, “Starting null thread?”);

//事实上,如果native_thread的osthread为NULL,就可以宣告整个线程创建过程失败 //这时应该整理内存,并通知java层线程创建失败

if (native_thread-gt;osthread() NULL)

// No one should hold a reference to the ‘native_thread’.

delete native_thread;

if (JvmtiExport::should_post_resource_exhausted())

JvmtiExport::post_resource_exhausted(

JVMTI_RESOURCE_EXHAUSTED_OOM_ERROR | JVMTI_RESOURCE_EXHAUSTED_THREADS,

“unable to create new native thread”);

THROW_MSG(vmSymbols::java_lang_OutOfMemoryError(),

“unable to create new native thread”);

Thread::start(native_thread);

JVM_END

关于thread_entry方法的补充:注意,这个方法非常重要,后面还会出现,所以我们留到后面再解释。

然后我们来看一下JVM在这个宏里面做了什么:

申请一个锁

创建一个JavaThread对象【见第二节】

如果有异常情况,抛出异常

对第二步的JavaThread类,做一个准备操作:thread.cpp$JavaThread::prepare

调用Thread::start方法,让一条线程开始运行

2、JavaThread对象的创建

本节是接上面小节中间,关于JavaThread对象创建的讲述的。

JavaThread是Java层的线程与平台层线程中间的一个过渡:

一个java.lang.Thread对象,在其start方法中,会创建一个JavaThread对象,由于java.lang.Thread对象的start方法只允许调用一次,所以java.lang.Thread对象与JavaThread对象是一一对应的

而在JavaThread对象的创建过程,会创建一个OSThread对象,并且JavaThread对象会持有一个指向该OSThread对象的指针(至于什么是OSThread,大概是平台相关的系统层线程,更详细见第三节)

thread.cpp$JavaThread::JavaThread :

JavaThread::JavaThread(ThreadFunction entry_point, size_t stack_sz) :

Thread()

if INCLUDE_ALL_GCS

, _satb_mark_queue(amp;_satb_mark_queue_set),

_dirty_card_queue(amp;_dirty_card_queue_set)

endif // INCLUDE_ALL_GCS

if (TraceThreadEvents)

tty-gt;print_cr(“creating thread %p”, this);

initialize();

_jni_attach_state = _not_attaching_via_jni;

set_entry_point(entry_point);

// Create the native thread itself.

// %note runtime_23

os::ThreadType thr_type = os::java_thread;

thr_type = entry_point amp;compiler_thread_entry ? os::compiler_thread :

os::java_thread;

os::create_thread(this, thr_type, stack_sz);

// 在这里,由于内存不足的原因,_osthread有可能为NULL、

// 而我们应当抛出OutOfMenoryError,然而现在我们还不能抛出Error

// 因为此方法的调用者有可能扔持有着所有的锁,而我们必须释放所有的锁才能抛出后异常

// (抛出异常的工作包括:创建并初始化一个exception对象,而初始化exception对象则必须要通过JavaCall离开VM,

// 然后所有的锁都必须要被释放)

//

// 此时这条线程扔处在挂起的状态,而线程必须由创建者显式地启动!

// 此外,线程还必须显式地通过Threads:add方法被添加到Threads list 中。

// 上面的工作(显式启动,显式添加)之所以到达这里还没完成,是因为线程还没有被完成地初始化(可参见JVM_Start)

完成的操作有:

调用initialize方法对JavaThread进行初始化,此方法仅是对结构体的属性做赋值;

为这个JavaThread设置一个入口方法set_entry_point

根据平台调用os::create_thread()方法来创建一个OSThread对象【见第三节】

3、根据平台创建OSThread

在这一步中,OSThread的创建是根据平台来选择,这里我是使用Linux部分的代码来进行研究的

OSThread是一个平台相关线程,OSThread由JavaThread对象创建并进行管理。

在OSThread创建的过程中,会通过pthread方法来创建一个真正意义上的底层级线程,

os_linux.cpp$os::create_thread:

这个方法传入三个参数:

第一个是我们之前在JavaThread构造方法中创建的JavaThread对象;

第二个是一个ThreadType对象,只有两种可能,一种是os::compiler_thread,另一种是os::java_thread

第三个是,线程栈的深度(猜测)

bool os::create_thread(Thread* thread, ThreadType thr_type, size_t stack_size)

assert(thread-gt;osthread() NULL, “caller responsible”);

// 为OSThread对象分配内存

OSThread* osthread = new OSThread(NULL, NULL);

//(注:)关于这个构造方法,并没有做出特殊的操作,仅是初始化一些属性,详见下方补充

if (osthread NULL)

return false;

// 设置正确的状态

osthread-gt;set_thread_type(thr_type);

// 初始状态应该是ALLOCATED 而不是INITIALIZED

osthread-gt;set_state(ALLOCATED);

//使得JavaThread的osthread指针指向新建的osthread

thread-gt;set_osthread(osthread);

// 初始化线程

pthread_attr_t attr;

pthread_attr_init(amp;attr);

pthread_attr_setdetachstate(amp;attr, PTHREAD_CREATE_DETACHED);

// stack size

if (os::Linux::supports_variable_stack_size())

// 如果调用者没有指定stack size,那么就需要对这个stack size进行计算

if (stack_size 0)

stack_size = os::Linux::default_stack_size(thr_type);

switch (thr_type) case os::java_thread: // Java threads use ThreadStackSize which default value can be // changed with the flag -Xss assert (JavaThread::stack_size_at_create() gt; 0, "this should be set"); stack_size = JavaThread::stack_size_at_create(); break; case os::compiler_thread: if (CompilerThreadStackSize gt; 0) stack_size = (size_t)(CompilerThreadStackSize * K); break; // else fall through: // use VMThreadStackSize if CompilerThreadStackSize is not defined case os::vm_thread: case os::pgc_thread: case os::cgc_thread: case os::watcher_thread: if (VMThreadStackSize gt; 0) stack_size = (size_t)(VMThreadStackSize * K); break; stack_size = MAX2(stack_size, os::Linux::min_stack_allowed); pthread_attr_setstacksize(amp;attr, stack_size);

else

// let pthread_create() pick the default value.

// glibc guard page

pthread_attr_setguardsize(amp;attr, os::Linux::default_guard_size(thr_type));

ThreadState state;

// Serialize thread creation if we are running with fixed stack LinuxThreads

// (好吧,我也不是很懂这句注释的意思,

// 尝试着直译一下:如果我们正在运行的是固定stack的LinuxThreads,那么就序列化线程的创建过程)

bool lock = os::Linux::is_LinuxThreads() amp;amp; !os::Linux::is_floating_stack();

if (lock)

os::Linux::createThread_lock()-gt;lock_without_safepoint_check();

pthread_t tid; int ret = pthread_create(amp;tid, amp;attr, (void* (*)(void*)) java_start, thread); //(注:)这个方法是c在Linux下创建并执行一个平台层的线程的方法 // 新建好的线程,应该执行的是java_start方法(即第二个参数) //如果返回值是0,表示线程创建成功,否则表示线程创建失败,关于这个方法的详细介绍,见下方补充 pthread_attr_destroy(amp;attr); // 下面是平台级线程创建失败的一些处理 // 如果osthread创建失败,就把JAVAThread的osthread设置为NULL if (ret != 0) if (PrintMiscellaneous amp;amp; (Verbose || WizardMode)) perror("pthread_create()"); // Need to clean up stuff we've allocated so far thread-gt;set_osthread(NULL); delete osthread; if (lock) os::Linux::createThread_lock()-gt;unlock(); return false; // Store pthread info into the OSThread // 这个tid是刚才新建的底层级线程的一个标识符,我们需要通过这个标识符来管理底层级线程 osthread-gt;set_pthread_id(tid); // 在这里停顿!直到子线程的初始化完成,或者子线程被放弃(考虑到线程中还有线程的情况) Monitor* sync_with_child = osthread-gt;startThread_lock(); MutexLockerEx ml(sync_with_child, Mutex::_no_safepoint_check_flag); while ((state = osthread-gt;get_state()) ALLOCATED) sync_with_child-gt;wait(Mutex::_no_safepoint_check_flag); if (lock) os::Linux::createThread_lock()-gt;unlock();

// Aborted due to thread limit being reached

if (state ZOMBIE)

thread-gt;set_osthread(NULL);

delete osthread;

return false;

// The thread is returned suspended (in state INITIALIZED),

// and is started higher up in the call chain

assert(state INITIALIZED, “race condition”);

return true;

补充OSThread::OSThread:

OSThread::OSThread(OSThreadStartFunc start_proc, void* start_parm)

pd_initialize();

//这个方法更是没有什么好讲的,只是将值初始化为初始值(及0或NULL)

//要是要看的话,这个方法在os/linux/vm/osThread_linux.cpp

set_start_proc(start_proc);

set_start_parm(start_parm);

set_interrupted(false);

补充创建系统级线程的pthread_create()方法

这个方法很长,做了以下的几件事:

1、 创建一个osthread对象,并初始化这个对象,这个初始化包括:设置thread_type,设置线程状态

2、让我们传进来的JavaThread对象保存这个osthread对象的引用

3、中间还有一些设置线程栈数量,获取锁之类的操作

4、864行,int ret = pthread_create(amp;tid, amp;attr, (void ()(void*)) java_start, thread);这个方法是C++创建线程的库方法,通过调用这个方法,会创建一个C++ 线程并使线程进入就绪状态,即可以开始运行

5、这个线程将执行java_start这个方法【见第四节】

6、开始收尾,清理一下内存

4、java_start方法

这个方法是OSThread创建的底层级线程中将要执行的方法,它的描述是:为所有新建的线程启动例程

os_linux.cpp$java_start

// 线程为所有新创建的线程启动例程。

static void *java_start(Thread *thread)

// Try to randomize the cache line index of hot stack frames.

// This helps when threads of the same stack traces evict each other’s

// cache lines. The threads can be either from the same JVM instance, or

// from different JVM instances. The benefit is especially true for

// processors with hyperthreading technology.

static int counter = 0;

int pid = os::current_process_id();

alloca(((pid ^ counter++) amp; 7) * 128);

ThreadLocalStorage::set_thread(thread);

OSThread* osthread = thread-gt;osthread();

Monitor* sync = osthread-gt;startThread_lock();

// non floating stack LinuxThreads needs extra check, see above

if (!_thread_safety_check(thread))

// notify parent thread

MutexLockerEx ml(sync, Mutex::_no_safepoint_check_flag);

osthread-gt;set_state(ZOMBIE);

sync-gt;notify_all();

return NULL;

// thread_id is kernel thread id (similar to Solaris LWP id)

osthread-gt;set_thread_id(os::Linux::gettid());

if (UseNUMA)

int lgrp_id = os::numa_get_group_id();

if (lgrp_id != -1)

thread-gt;set_lgrp_id(lgrp_id);

// initialize signal mask for this thread

os::Linux::hotspot_sigmask(thread);

// initialize floating point control register

os::Linux::init_thread_fpu_state();

// 与父进程进行新号交互(handshaking)

MutexLockerEx ml(sync, Mutex::_no_safepoint_check_flag);

// 通知父线程 osthread-gt;set_state(INITIALIZED); sync-gt;notify_all(); // wait until os::start_thread() while (osthread-gt;get_state() INITIALIZED) sync-gt;wait(Mutex::_no_safepoint_check_flag);

// 调用一个更高级别的开始例程(见第五节)

thread-gt;run();

return 0;

这个方法做的事:

1、拿到这个线程的线程id

2、分配内存?

3、设置ThreadLocal

4、线程安全检测

5、中间还有一些东西,不想关心

6、同样地,再次设置这个thread的osthrad的状态

7、调用Thread的run方法,但是这个run方法是个虚方法,实际上调用的是JavaThread的run方法【见第五节】

5、JavaThread::run()

JavThread::run():

// Java Thread第一个调用的例程

void JavaThread::run()

//初始化相关字段

// initialize thread-local alloc buffer related fields

this-gt;initialize_tlab();

// used to test validitity of stack trace backs

this-gt;record_base_of_stack_pointer();

// Record real stack base and size.

this-gt;record_stack_base_and_size();

// Initialize thread local storage; set before calling MutexLocker

this-gt;initialize_thread_local_storage();

this-gt;create_stack_guard_pages();

this-gt;cache_global_variables();

//线程基本初始化完成,在虚拟机中可以当作是safepoint代码来处理了 //于是将线程的状态从 _thread_new切换到_thread_in_vm

// Thread is now sufficient initialized to be handled by the safepoint code as being

// in the VM. Change thread state from _thread_new to _thread_in_vm

ThreadStateTransition::transition_and_fence(this, _thread_new, _thread_in_vm);

assert(JavaThread::current() this, “sanity check”);

assert(!Thread::current()-gt;owns_locks(), “sanity check”);

DTRACE_THREAD_PROBE(start, this);

// This operation might block. We call that after all safepoint checks for a new thread has

// been completed.

//这个操作有可能会被阻塞,我们需要要在所有safepoint检查完这个新线程以后才能调用此方法

this-gt;set_active_handles(JNIHandleBlock::allocate_block());

if (JvmtiExport::should_post_thread_life())

JvmtiExport::post_thread_start(this);

EventThreadStart event;

if (event.should_commit())

event.set_javalangthread(java_lang_Thread::thread_id(this-gt;threadObj()));

// We call another function to do the rest so we are sure that the stack addresses used

// from there will be lower than the stack base just computed

thread_main_inner();

// 注意,一旦运行到这里,线程就不再合法(valid)了

这个方法完成的事有:

1、初始化相关字段

2、将线程的状态从 _thread_new切换到_thread_in_vm

3、调用thread_main_inner()方法【见第六节】

(这里说的safepoint应该就是GC中要用到的safepoint吧,但是all safepoint checks for a new thread是什么意思,safepoint还能检查线程..?暂且搁置)

6、JavaThread::thread_main_inner()

void JavaThread::thread_main_inner()

assert(JavaThread::current() this, “sanity check”);

assert(this-gt;threadObj() != NULL, “just checking”);

// Execute thread entry point unless this thread has a pending exception

// or has been stopped before starting.

// Note: Due to JVM_StopThread we can have pending exceptions already!

if (!this-gt;has_pending_exception() amp;amp;

!java_lang_Thread::is_stillborn(this-gt;threadObj()))

ResourceMark rm(this);

this-gt;set_native_thread_name(this-gt;get_thread_name());

HandleMark hm(this);

this-gt;entry_point()(this, this);

DTRACE_THREAD_PROBE(stop, this);

this-gt;exit(false);

delete this;

然后有回到了之前的我们设置的entry_point():

thread_entry方法的补充:

static void thread_entry(JavaThread* thread, TRAPS)

HandleMark hm(THREAD);

Handle obj(THREAD, thread-gt;threadObj());

JavaValue result(T_VOID);

JavaCalls::call_virtual(amp;result,

obj,

KlassHandle(THREAD, SystemDictionary::Thread_klass()),

vmSymbols::run_method_name(),`

THREAD);

注意这个vmSymbols::run_method_name(),非常关键!

这个方法是在vmSymbolHandles中用宏来定义的,而这个vmSymbolHandles的描述是:

// The class vmSymbols is a name space for fast lookup of

// symbols commonly used in the VM.

//

// Sample usage:

//

// Symbol* obj = vmSymbols::java_lang_Object();

大意翻译为:vmSymbols是一个VM中使用的,用于常用符号的快速查找的命名空间

于是,我们在这个命名空间找到了这样的一行代码:

template(run_method_name, “run”)

也就是说,这里调用的是java.lang.Thread对象的run()方法!

总结

撇开源码,整个过程大概是:

在Java中,使用java.lang.Thread的构造方法来构建一个java.lang.Thread对象,此时只是对这个对象的部分字段(例如线程名,优先级等)进行初始化;

调用java.lang.Thread对象的start()方法,开始此线程。此时,在start()方法内部,调用start0() 本地方法来开始此线程;

start0()在VM中对应的是JVM_StartThread,也就是,在VM中,实际运行的JVM_StartThread方法(宏),在这个方法中,创建了一个JavaThread对象;

在JavaThread对象的创建过程中,创建一个OSThread对象,且JavaThread保持这个OSThread对象的引用;

在OSThread对象的创建过程中,创建一个平台相关的底层级线程,如果这个底层级线程失败,那么就抛出异常;

这个底层级的线程开始运行,并执行java.lang.Thread对象的run方法;

当java.lang.Thread生成的Object的run()方法执行完毕返回后,或者抛出异常终止后,终止native thread;

最后就是释放相关的资源(包括内存、锁等)

大家可以点击加入群:478052716【JAVA高级程序员】里面有Java高级大牛直播讲解知识点 走的就是高端路线 (如果你想跳槽换工作 但是技术又不够 或者工作上遇到了瓶颈 我这里有一个JAVA的免费直播课程 讲的是高端的知识点基础不好的误入哟 只要你有1-5年的开发经验可以加群找我要课堂链接 注意:是免费的 没有开发经验误入哦)

郑重声明:此文内容为本网站转载企业宣传资讯,目的在于传播更多信息,与本站立场无关。仅供读者参考,并请自行核实相关内容。

相关内容

  • 双向对飞、夕发朝至!京东航空“北京大兴深圳”货运航线开通

    双向对飞、夕发朝至!京东航空“北京大兴深圳”货运航线开通

  • 全蝎疗法发明人——孙纯孝

    全蝎疗法发明人——孙纯孝

  • 科学没有疆界,科学家却有祖国——沪上两位科学家深情讲述动人心

    科学没有疆界,科学家却有祖国——沪上两位科学家深情讲述动人心

专题报道