Почему многопоточный запуск Java вызывает метод start() вместо метода run()?

Java

Многопоточность в большей или меньшей степени будет использоваться в работе, мы знаем с чего начатьМногопоточность вызывает метод start() вместо метода run(), знаете почему?

Прежде чем обсуждать этот вопрос, давайте сначала разберемся с некоторыми базовыми знаниями о многопоточности~

состояние потока

В Java определены 6 состояний потока, которые можно найти в классе Thread:

// 为了节约空间,我删除了注释
public enum State {
       NEW,//初始状态
       RUNNABLE,//运行状态
       BLOCKED,// 阻塞状态
       WAITING,//等待状态
       TIMED_WAITING,//超时等待状态
       TERMINATED;//终止状态
 }

Отношения между этими 6 состояниями можно увидеть на следующем рисунке:

图片来源网络

Эта картинка очень подробная, в сочетании с этой картинкой поговорим о том, что означают эти состояния:

  • 1,NEW означает, что поток был успешно создан, но не запущен., после создания нового потока перед запуском поток находится в состоянии NEW;
  • 2,RUNNABLE означает, что поток запущен., когда мы запускаем метод strat и дочерний поток успешно создается, состояние дочернего потока становится RUNNABLE;
  • 3.TERMINATED означает, что выполнение потока завершено., дочерний поток завершается, прерывается и прерывается, а статус изменяется с RUNNABLE на TERMINATED;
  • 4.BLOCKED означает, что поток заблокирован, если поток просто ожидает получения блокировки монитора, например, ожидания ввода синхронизированного измененного блока кода или метода, он изменится с RUNNABLE на BLOCKED;
  • 5.И WAITING, и TIMED_WAITING означают ожидание., теперь сталкиваемся с Object#wait, Thread#join, LockSupport#паркует эти методы, поток будет ждать, пока другой поток выполнит определенное действие, прежде чем он сможет завершиться Нет ожидания, но TIMED_WAITING имеет время ожидания;

приоритет

Приоритет представляет размер возможности для выполнения потока.Более высокий приоритет может быть выполнен первым, а более низкий может быть выполнен позже.

В исходном коде Java приоритет составляет от 1 до 10 от низкого к высокому, а приоритет нового потока по умолчанию равен 5. Исходный код выглядит следующим образом:

 /**
  * The minimum priority that a thread can have.
  */
 public final static int MIN_PRIORITY = 1;

/**
  * The default priority that is assigned to a thread.
  */
 public final static int NORM_PRIORITY = 5;

 /**
  * The maximum priority that a thread can have.
  */
 public final static int MAX_PRIORITY = 10;

Как создается ветка

Мы создаем многопоточность двумя способами: один — наследовать класс Thread, а другой — реализовывать интерфейс Runnable. Использование двух способов заключается в следующем:

1. Наследовать Thread и стать подклассом Thread

public class MyThread extends Thread{
    @Override
    public void run() {
        System.out.println("我是通过继承 Thread 类实现的~");
    }

    public static void main(String[] args) {
        MyThread thread = new MyThread();
        // 启动线程
        thread.start();
    }
}

2. Реализуйте интерфейс Runnable

public class MyThread1 {
    public static void main(String[] args) {
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("我是通过 runnable 方式实现的~");
            }
        });
        // 启动线程
        thread.start();
    }
}

Независимо от того, какой метод используется, запуск потокаthread.start()метод, если вы поэкспериментируете, вы найдетеthread.run()Его тоже можно выполнить, зачем вам вызыватьthread.start()как насчет метода?

Сначала поговорим о заключении:сначала через对象.run()Метод может выполнять метод, но вместо использования многопоточного способа, это общий подход, многопоточный подход для достижения, тогда нам нужно对象.start()метод.

Если вы хотите понять проблему, лучше всего начать с исходного кода., мы также начинаем с исходного кода этих двух методов, давайте взглянем на исходный код метода запуска:

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. */
    group.add(this);
	// 是否启动的标识符
    boolean started = false;
    try {
	    // start0() 是启动多线程的关键
	    // 这里会创建一个新的线程,是一个 native 方法
	    // 执行完成之后,新的线程已经在运行了
        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 */
        }
    }
}

Исходный код метода start состоит из нескольких строк, а также подробных комментариев, наиболее важным из которых является метод start0(), который будет объяснен позже. Давайте посмотрим на исходный код метода run():

    @Override
    public void run() {
	    // 简单的运行,不会新起线程,target 是 Runnable
        if (target != null) {
            target.run();
        }
    }

Исходный код метода run() относительно прост и представляет собой вызов общего метода, что также подтверждает наш вывод, сделанный выше.

Далее поговорим о методе start0(), который является ключом к настоящей многопоточности.Код start0() выглядит следующим образом:

private native void start0();

start0 помечен как native , то есть нативный метод, и нам не нужно реализовывать или понимать, **почему start0() будет помечен как native**?

Это начинается с кроссплатформенности Java, посмотрите на следующую картинку:

图片来源牛客网

После того, как метод start() вызывает метод start0(), поток не обязательно выполняется немедленно, а только переводит поток в состояние, пригодное для выполнения. Когда его выполнять, зависит от ЦП, который равномерно планируется ЦП.

Мы также знаем, что Java является кроссплатформенной и может работать на разных системах.Алгоритм планирования процессора каждой системы отличается, поэтому он должен обрабатываться по-разному.Это может сделать только JVM, start0() Метод естественно отмечен как родной.

наконецПодводя итог, настоящая многопоточность в Java — это метод start0() в start, а метод run() — обычный метод.