一、简介
在Java代码当中,当我们需要开启子线程去处理一些任务的时候,往往是调用Thread对象的start方法,这样Thread实例中的Runnable对象的run方法就会在一个新的线程当中执行;
// 创建一个线程
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("working in " + Thread.currentThread().getName());
}
});
// 在什么线程调用,run方法的任务就在什么线程执行
thread.run();
// 在一个新的线程中执行run方法中的任务
thread.start();
二、分析run()方法
如下代码可见,当我们直接调用run方法的时候,就相当于实例直接调用一个普通的方法一样,所以无论我们在什么线程中调用run方法,run方法中的业务就在什么线程执行,并不会说启动一个新的线程去执行run方法中的任务;
// Thread.class中的run方法,target为Runnable实例
@Override
public void run() {
if (target != null) {
target.run();
}
}
三、分析start()方法
如下我们直接来看Thread.class中的代码;
public synchronized void start() {
/**
* 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.
*
* A zero status value corresponds to state "NEW".
*/
if (threadStatus != 0)
throw new IllegalThreadStateException();
/* Notify the group that this thread is about to be started
* so that it can be added to the group's list of threads
* and the group's unstarted count can be decremented. */
// 1. 将当前线程实例添加到ThreadGroup对象group中
group.add(this);
boolean started = false;
try {
// 2. 调用native方法start0()
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 */
}
}
}
// native 方法
private native void start0();
看上面代码的注释1那里,我们来看下Thread.class代码里面group是哪里来的
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();
// 1. 从System类中获取安全管理器
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) {
// 2. 从安全管理器中过去ThreadGroup对象
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;
// 省略一部分代码
···
}
从上面注释1,2可以看出,Thread实例中的ThreadGroup实例g主要是从底层代码中获取的,即group.add(this)执行之后,将当前线程传给了底层系统去管理
下面看下start0()方法,因为start0()方法为Native方法,看下是怎么实现的,如下为src/main/native/Thread.c的代码
static JNINativeMethod methods[] = {
// 从这里我们可以看到start0方法主要JVM_StartThread的一个方法引用
{
"start0", "(JZ)V", (void *)&JVM_StartThread},
{
"setPriority0", "(I)V", (void *)&JVM_SetThreadPriority},
{
"yield", "()V", (void *)&JVM_Yield},
{
"sleep", "(Ljava/lang/Object;J)V", (void *)&JVM_Sleep},
{
"currentThread", "()" THD, (void *)&JVM_CurrentThread},
{
"interrupt0", "()V", (void *)&JVM_Interrupt},
{
"isInterrupted", "(Z)Z", (void *)&JVM_IsInterrupted},
{
"holdsLock", "(" OBJ ")Z", (void *)&JVM_HoldsLock},
{
"setNativeName", "(" STR ")V", (void *)&JVM_SetNativeThreadName},
};
下面一下JVM_StartThread的情况
// 如下为/openjdkjvm/OpenjdkJvm.cc中的代码
JNIEXPORT void JVM_StartThread(JNIEnv* env, jobject jthread, jlong stack_size, jboolean daemon) {
art::Thread::CreateNativeThread(env, jthread, stack_size, daemon == JNI_TRUE);
}
// 如下为/runtime/thread.cc中创建native线程的代码
void Thread::CreateNativeThread(JNIEnv* env, jobject java_peer, size_t stack_size, bool is_daemon) {
···
// 这里就不做展开了
}
总结:从上面代码可以看出,Thread调用start的时候,将thread实例传给虚拟机持有,然后调用native创建一个新的线程,由虚拟机进行调度。
水平有限,有误请指正!