создание темы
Мы знаем, что в Java потокиjava.lang.Thread
класс для реализации. Как правило, мы используем следующие два метода для создания потока без возвращаемого значения:
- Унаследуйте класс Thread и переопределите метод run();
- Реализовать интерфейс Runnable и переопределить метод run();
Запуск потока запустит поток, вызвав метод запуска вместо прямого вызова метода запуска.
Вот два классических вопроса для интервью:
- Почему запуск потока заключается в вызове метода запуска для запуска потока, а не непосредственном вызове метода запуска?
- Что произойдет, если метод start будет вызван несколько раз?
На самом деле ответ есть в исходном коде, перед этим нам нужно знать, в каком состоянии находится поток.
состояние потока
Поток проходит несколько состояний от создания до смерти. они соответственно:NEW、RUNNABLE、BLOCKED、WAITING、TIMED_WAITING、TERMINATED
.
// Thread类的内部的枚举类定义了线程的状态
public enum State {
NEW,
RUNNABLE,
BLOCKED,
WAITING,
TIMED_WAITING,
TERMINATED;
}
метод start() и метод run()
Почему запуск потока заключается в вызове метода запуска для запуска потока, а не непосредственном вызове метода запуска?
Из рисунка выше видно, что после создания нового потока он сначала входит в начальное состояние, а затем вызывает метод start() для перехода в состояние готовности, при этом задачи в потоке не будут выполняться сразу , но будет ждать выделения системных ресурсов, когда будет выделен временной интервал, он может начать работать. Метод start() — это нативный метод, который запускает новый поток и выполняет метод run(), который действительно является многопоточным. Непосредственное выполнение метода run() приведет к выполнению метода run как обычного метода в основном потоке и не будет выполнять его в определенном потоке, поэтому это не многопоточная работа. Вот почему метод run() выполняется при вызове метода start() и почему метод run() нельзя вызвать напрямую.
Пример:
public class ThreadDemo
public static void main(String[] args) {
Thread t1 = new Thread(new Task1());
Thread t2 = new Thread(new Task2());
// 测试1
t1.start();
t2.start();
// 测试2
t1.run();
t2.run();
}
}
class Task1 implements Runnable {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("Task1: " + i);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class Task2 implements Runnable {
@Override
public void run() {
for (int i = 10; i > 0; i--) {
System.out.println("Task2: " + i);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
// 测试1输出
Task1: 0
Task2: 10
Task1: 1
Task2: 9
Task1: 2
Task2: 8
Task1: 3
Task2: 7
Task1: 4
Task2: 6
Task1: 5
Task2: 5
Task1: 6
Task2: 4
Task1: 7
Task2: 3
Task1: 8
Task2: 2
Task1: 9
Task2: 1
我们可以看到Task1 和 Task2是交替打印的,是多线程在运行。
// 测试2输出
Task1: 0
Task1: 1
Task1: 2
Task1: 3
Task1: 4
Task1: 5
Task1: 6
Task1: 7
Task1: 8
Task1: 9
Task2: 10
Task2: 9
Task2: 8
Task2: 7
Task2: 6
Task2: 5
Task2: 4
Task2: 3
Task2: 2
Task2: 1
这个的输出是串行的,Task1 执行完才执行 Task2,所以不是多线程,是普通方法。
Что произойдет, если метод start будет вызван несколько раз?
Давайте сначала протестируем.
Пример:
public class ThreadDemo
public static void main(String[] args) {
Thread t1 = new Thread(new Task1());
Thread t2 = new Thread(new Task2());
// 测试3
t1.start();
t1.start();
}
}
// 测试3输出
Task1: 0
Task...
Exception in thread "main" java.lang.IllegalThreadStateException
at java.lang.Thread.start(Thread.java:708)
Task...
Только первое успешное выполнение, потом выбрасывается исключениеjava.lang.IllegalThreadStateException
, давайте взглянем на следующий исходный код.После того, как приходит метод запуска, он будет судить о состоянии потока.Если это не начальное состояние, будет выдано исключение, поэтому второе выполнение сообщит об ошибке, потому что состояние потока было изменено.
исходный код
Исходный код метода start():
public synchronized void start() {
// 如果线程不是"NEW状态",则抛出异常!
if (threadStatus != 0)
throw new IllegalThreadStateException();
// 将线程添加到ThreadGroup中
group.add(this);
boolean started = false;
try {
// 通过start0()启动线程,新线程会调用run()方法
start0();
// 设置started标记=true
started = true;
} finally {
try {
if (!started) {
group.threadStartFailed(this);
}
} catch (Throwable ignore) {
}
}
}
Исходный код метода run:
public void run() {
if (target != null) {
target.run();
}
}
Суммировать
Метод start() используется для запуска потока, который действительно реализует многопоточную работу.
Метод run() является обычным методом.
После вызова метода start() он сначала определяет, является ли состояние потока НОВЫМ, поэтому поток можно запустить только один раз.
В этой статье используетсяmdniceнабор текста