Многопоточность в большей или меньшей степени будет использоваться в работе, мы знаем с чего начатьМногопоточность вызывает метод 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() — обычный метод.