Home  >  Article  >  Java  >  A closer look at the right and wrong ways to start threads in Java

A closer look at the right and wrong ways to start threads in Java

coldplay.xixi
coldplay.xixiforward
2020-09-28 16:55:092101browse

A closer look at the right and wrong ways to start threads in Java

A closer look at the correct and incorrect ways to start threads in Java

Review of the previous article

  1. Detailed analysis of the methods of implementing multi-threading in Java are How many? (Based on the essence)

Comparison of start method and run method

Code demonstration:

/**
 * <p>
 * start() 和 run() 的比较
 * </p>
 *
 * @author 踏雪彡寻梅
 * @version 1.0
 * @date 2020/9/20 - 16:15
 * @since JDK1.8
 */public class StartAndRunMethod {    public static void main(String[] args) {        // run 方法演示
        // 输出: name: main
        // 说明由主线程去执行的, 不符合新建一个线程的本意
        Runnable runnable = () -> {
            System.out.println("name: " + Thread.currentThread().getName());
        };
        runnable.run();        // start 方法演示
        // 输出: name: Thread-0
        // 说明新建了一个线程, 符合本意
        new Thread(runnable).start();
    }
}复制代码

From the above example The following two points can be analyzed:

  • Directly using the run method will not start a new thread. (wrong way)

  • start method starts a new thread. (Correct way)

start method analysis

The meaning of the start method and precautions

  • start method can start a new thread.

    • After the thread object calls the start method after initialization, the current thread (usually the main thread) will request the JVM virtual machine to start this if it is free. New thread.
    • In other words, the essence of starting a new thread is to request the JVM to run the thread.
    • As for when this thread can run, it is not simply decided by us, but by the thread scheduler.
    • If it is very busy, even if we run the start method, we may not be able to start the thread immediately.
    • So after the srtart method is called, it does not mean that this method has started running. It may not run until later, or it may not run for a long time, such as in case of starvation.
    • This also proves that in some cases, thread 1 first calls the start method, and then thread 2 calls the start method, only to find that thread 2 first The situation of execution after executing thread 1.
    • Summary: The order in which the start method is called does not determine the order in which the actual threads are executed.
    • Note
      • start method will involve two threads.
      • The first one is the main thread, because we must have a main thread or other threads (even if it is not the main thread) to execute this start method, the second one is the new one the rout.
      • In many cases, the main thread that creates the thread for us will be ignored. Don't mistakenly think that calling start is already executed by the child thread. This statement is actually the main thread or the main thread. It is executed by the parent thread, and a new thread is created after it is executed.
  • start Method to create a new thread preparations

    • First, it will make itself In ready state.
      • The ready state means that other resources besides the CPU have been obtained, such as the context, stack, thread status and PC (PC is a register, PC points to the location where the program is running), etc. have been set.
    • After completing these preparations, everything is ready and all you need is Dongfeng, which is the CPU resource.
    • After completing the preparation work, the thread can be further scheduled by the JVM or operating system to the execution state to wait for CPU resources, and then it will actually enter the running state to execute the run method. code.
  • Note: The start method cannot be executed repeatedly

    • Code example

      /**
      * <p>
      * 演示不能重复的执行 start 方法(两次及以上), 否则会报错
      * </p>
      *
      * @author 踏雪彡寻梅
      * @version 1.0
      * @date 2020/9/20 - 16:47
      * @since JDK1.8
      */public class CantStartTwice {    public static void main(String[] args) {
              Runnable runnable = () -> {
                  System.out.println("name: " + Thread.currentThread().getName());
              };
              Thread thread = new Thread(runnable);        // 输出: name: Thread-0
              thread.start();        // 输出: 抛出 java.lang.IllegalThreadStateException
              // 即非法线程状态异常(线程状态不符合规定)
              thread.start();
          }
      }复制代码
    • Cause of error

      • start Once execution starts, the thread state will enter the subsequent state from the initial New state, such as Runnable, and then Once the thread completes execution, the thread will become a terminated state, and the terminated state can never be returned, so the above exception will be thrown, which means that it cannot return to the initial state. The description here is not clear enough. Let's take a look at the source code to understand more thoroughly.

start method source code analysis

Source code

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&#39;s list of threads
     * and the group&#39;s unstarted count can be decremented. */
    // 第二步, 加入线程组
    group.add(this);    boolean started = false;    try {        // 第三步, 调用 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 */
        }
    }
}复制代码

Process in the source code

Step one: When starting a new thread, it will first check whether the thread state is the initial state, which is also the reason why the above exception is thrown. That is, the following code:

if (threadStatus != 0)    throw new IllegalThreadStateException();复制代码

Among them, threadStatus The annotation of this variable is as follows, which means that the Java thread status is initially expressed as 0 (not yet started):

/* Java thread status for tools,
 * initialized to indicate thread &#39;not yet started&#39;
 */private volatile int threadStatus = 0;复制代码

Step 2:Add it to the thread group. That is, the following code:

group.add(this);复制代码

The third step:Finally call start0() This native method (native means that its code is not implemented by Java, but by C/C implementation, the specific implementation can be seen in the JDK, just understand it), that is, the following code:

boolean started = false;try {    // 第三步, 调用 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 */
    }
}复制代码

run method analysis

run method source code analysis

@Overridepublic void run() {    // 传入了 target 对象(即 Runnable 接口的实现), 执行传入的 target 对象的 run 方法
    if (target != null) {
        target.run();
    }
}复制代码

Two situations for the run method

  • The first one: Overriding the run method of the Thread class, Thread's run method will be invalid, and the overridden run method will be executed.

  • Second type: Pass in the target object (that is, the implementation of the Runnable interface) and execute the original # of Thread The ##run method then proceeds to execute the run method of the target object.

  • Summary: The

    • #run method is an ordinary method. The run method is directly executed above. It is equivalent to executing the ordinary method we wrote ourselves, so its execution thread is our main thread.
    • So if you want to actually start the thread, you cannot call the
    • run method directly, but you must call the start method, in which you can call run## indirectly. # method.
Related learning recommendations:

java basics

The above is the detailed content of A closer look at the right and wrong ways to start threads in Java. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:juejin.im. If there is any infringement, please contact admin@php.cn delete