Why use the start method to start Java's Thread thread?

1. Introduction

In Java code, when we need to start a child thread to process some tasks, we often call the start method of the Thread object, so that the run method of the Runnable object in the Thread instance will be executed in a new thread;

// 创建一个线程
Thread thread = new Thread(new Runnable() {
    
    
			
	@Override
	public void run() {
    
    
		System.out.println("working in " + Thread.currentThread().getName());
	}
});

// 在什么线程调用,run方法的任务就在什么线程执行
thread.run();

// 在一个新的线程中执行run方法中的任务
thread.start();

Second, analyze the run () method

As can be seen from the following code, when we directly call the run method, it is equivalent to calling a common method directly by the instance, so no matter what thread we call the run method in, the business in the run method will be executed in which thread, and will not Said to start a new thread to execute the tasks in the run method;

// Thread.class中的run方法,target为Runnable实例
@Override 
public void run() {
    
    
    if (target != null) {
    
    
        target.run();
    }
}

Three, analyze the start () method

Let's look directly at the code in Thread.class as follows;

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();

Look at Note 1 of the above code, let's see where the group in the Thread.class code comes from

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;
        
    // 省略一部分代码
    ···
}

It can be seen from the above notes 1 and 2 that the ThreadGroup instance g in the Thread instance is mainly obtained from the underlying code, that is, after group.add(this) is executed, the current thread is passed to the underlying system for management

Let's look at the start0() method, because the start0() method is a Native method, let's see how it is implemented, the code of src/main/native/Thread.c is as follows

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},
};

Let's look at the situation of 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) {
    
    
    ···
    // 这里就不做展开了
}

Summary: As can be seen from the above code, when Thread calls start, it passes the thread instance to the virtual machine to hold, and then calls native to create a new thread, which is scheduled by the virtual machine.

The level is limited, please correct me if I am wrong!

Guess you like

Origin blog.csdn.net/qq_36224961/article/details/124304820