为什么使用start方法启动Java的Thread线程?

一、简介

在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创建一个新的线程,由虚拟机进行调度。

水平有限,有误请指正!

猜你喜欢

转载自blog.csdn.net/qq_36224961/article/details/124304820