Статья 5 из серии о многопоточности в Java.
что такое нить
Представьте, как будет выглядеть программа без потоков? Сетевой диск Baidu не может загрузить файл при загрузке файла и может загрузить файл после завершения загрузки файла. Сейчас это кажется нам очень античеловеческим, потому что мы привыкли к программе, которая может выполнять несколько функций одновременно, а это заслуга потоков.
предыдущая статьяКак много вы знаете о процессеЧтобы реализовать параллельное выполнение нескольких программ, вводится понятие процесса. Потоки теперь введены, чтобы позволить программе выполняться одновременно.
состав нитей
идентификатор потока: идентификатор потока.
Указатель текущей инструкции (ПК): Указывает на инструкцию, которую нужно выполнить.
набор регистров: Набор регистров ячеек памяти.
куча: временное хранение данных и адресов, обычно используемых для защиты точек останова и сайтов.
Разница между потоком и процессом
Разница между потоками и процессами, я думаю, этот пример можно использовать, чтобы увидеть разницу между ними, процесс — это дом, а дом живет с 3 людьми, а поток — это люди, которые живут в доме. Процесс — это независимый индивидуум со своими собственными ресурсами.Потоки находятся в процессе, и несколько потоков совместно используют ресурсы процесса.
состояние потока
Мы видим, что в исходном коде Java перечисление статуса потока выглядит следующим образом.
public enum State {
//新建状态
NEW,
//运行状态
RUNNABLE,
//阻塞状态
BLOCKED,
//等待状态
WAITING,
//等待状态(区别在于这个有等待的时间)
TIMED_WAITING,
//终止状态
TERMINATED;
}
Шесть состояний объясняются ниже.
NEW: Новое состояние. Прежде чем поток будет создан и start() не будет выполнен, состояние потока всегда будет НОВЫМ. Можно сказать, что в настоящее время не отображается реальный поток, а просто объект.
RUNNABLE: Рабочий статус. После того как объект потока вызывает start(), он переходит в состояние RUNNABLE, что указывает на наличие реального потока в JVM.
BLOCKED: Состояние блокировки. Поток ожидает снятия блокировки, то есть ожидает получения блокировки монитора.
WAITING: состояние ожидания. Когда поток находится в этом состоянии, ему не будет выделен ЦП, и его необходимо явно разбудить, иначе он будет ждать вечно.
TIMED_WAITING: Состояние ожидания тайм-аута. Поток в этом состоянии не будет выделять ЦП, но и не будет ждать бесконечно, есть ограничение по времени, и он перестанет ждать, когда время истечет.
TERMINATED: Прекращенное состояние. Выполнение потока завершено, но это не значит, что объект пропал, объект может еще существовать, а потока нет.
Поскольку у потока так много состояний, должен быть конечный автомат, то есть, при каких обстоятельствах состояние A станет состоянием B. Ниже приводится краткое описание.
В сочетании со следующим рисунком, когда мы создаем новый класс потока, этоNEW
государство, звонитеstart()метод, введитеRUNNABLE
состояние, в это время, если ожидание срабатывает, оно войдет вWAITING
состояние, если время ожидания триггера истекло, введитеTIMED_WAITING
состояние, при обращении к ресурсу, который необходимо синхронизировать, к нему может обращаться только один поток, а другие потоки входятBLOCKED
состояние, когда поток завершит выполнение, введитеTERMINATED
государство.
На самом деле в JVM существует 9 состояний потоков, как показано ниже, заинтересованные студенты могут узнать о них подробнее.
javaClasses.hpp
enum ThreadStatus {
NEW = 0,
RUNNABLE = JVMTI_THREAD_STATE_ALIVE + // runnable / running
JVMTI_THREAD_STATE_RUNNABLE,
SLEEPING = JVMTI_THREAD_STATE_ALIVE + // Thread.sleep()
JVMTI_THREAD_STATE_WAITING +
JVMTI_THREAD_STATE_WAITING_WITH_TIMEOUT +
JVMTI_THREAD_STATE_SLEEPING,
IN_OBJECT_WAIT = JVMTI_THREAD_STATE_ALIVE + // Object.wait()
JVMTI_THREAD_STATE_WAITING +
JVMTI_THREAD_STATE_WAITING_INDEFINITELY +
JVMTI_THREAD_STATE_IN_OBJECT_WAIT,
IN_OBJECT_WAIT_TIMED = JVMTI_THREAD_STATE_ALIVE + // Object.wait(long)
JVMTI_THREAD_STATE_WAITING +
JVMTI_THREAD_STATE_WAITING_WITH_TIMEOUT +
JVMTI_THREAD_STATE_IN_OBJECT_WAIT,
PARKED = JVMTI_THREAD_STATE_ALIVE + // LockSupport.park()
JVMTI_THREAD_STATE_WAITING +
JVMTI_THREAD_STATE_WAITING_INDEFINITELY +
JVMTI_THREAD_STATE_PARKED,
PARKED_TIMED = JVMTI_THREAD_STATE_ALIVE + // LockSupport.park(long)
JVMTI_THREAD_STATE_WAITING +
JVMTI_THREAD_STATE_WAITING_WITH_TIMEOUT +
JVMTI_THREAD_STATE_PARKED,
BLOCKED_ON_MONITOR_ENTER = JVMTI_THREAD_STATE_ALIVE + // (re-)entering a synchronization block
JVMTI_THREAD_STATE_BLOCKED_ON_MONITOR_ENTER,
TERMINATED = JVMTI_THREAD_STATE_TERMINATED
};
Реализация потока Java
Давайте поговорим о том, как создать поток в Java. Как мы все знаем, существует два способа реализации потоков Java: наследование класса Thread и реализация интерфейса Runnable.
Наследовать от класса Thread
Наследовать класс Thread, переопределитьrun()
метод.
class MyThread extends Thread {
@Override
public void run() {
System.out.println("MyThread");
}
}
Реализовать интерфейс Runnable
Реализовать интерфейс Runnable, реализоватьrun()
метод.
class MyRunnable implements Runnable {
public void run() {
System.out.println("MyRunnable");
}
}
Два потока запускаются по-разному.MyThread
это класс потока, поэтому вы можете напрямуюnew
из объекта, а затем вызовитеstart()
метод для запуска потока; в то время какMyRunnable
просто обычный класс, который беретnew
Базовый класс исходящего потокаThread
объект, воляMyRunnable
передается объект.
Вот как начать нить.
public class ThreadImpl {
public static void main(String[] args) {
MyThread myThread = new MyThread();
Thread myRunnable = new Thread(new MyRunnable());
System.out.println("main Thread begin");
myThread.start();
myRunnable.start();
System.out.println("main Thread end");
}
}
Результат печати следующий:
main Thread begin
main Thread end
MyThread
MyRunnable
Глядя на этот результат, в отличие от нашего предыдущего последовательного последовательного выполнения, основной поток не будет ждать завершения выполнения дочернего потока.
Стук в точку: нельзя вызвать напрямуюrun()
, звоните напрямуюrun()
Поток не создается, но основной поток выполняется напрямуюrun()
, что эквивалентно выполнению обычной функции. В настоящее время он выполняется серийно. См. код ниже.
public class ThreadImpl {
public static void main(String[] args) {
MyThread myThread = new MyThread();
Thread myRunnable = new Thread(new MyRunnable());
System.out.println("main Thread begin");
myThread.run();
myRunnable.run();
System.out.println("main Thread end");
}
}
распечатать результат:
main Thread begin
MyThread
MyRunnable
main Thread end
Из результатов видно, что это только последовательный вызов, но не видно, что потоков нет.Давайте рассмотрим следующий пример, чтобы проверить прямой вызовrun()
метод не создает новый поток, используйтеVisualVMинструмент для наблюдения за состоянием резьбы.
Внесем некоторые изменения в код, добавимThread.sleep(1000000)
Дайте ему поспать некоторое время, чтобы было удобно использовать инструменты для проверки ситуации с потоком.
перечислитьrun()
код:
public class ThreadImpl {
public static void main(String[] args) {
MyThread myThread = new MyThread();
myThread.setName("MyThread");
Thread myRunnable = new Thread(new MyRunnable());
myRunnable.setName("MyRunnable");
System.out.println("main Thread begin");
myThread.run();
myRunnable.run();
System.out.println("main Thread end");
try {
Thread.sleep(1000000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class MyThread extends Thread {
@Override
public void run() {
System.out.println("MyThread");
try {
Thread.sleep(1000000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class MyRunnable implements Runnable {
public void run() {
System.out.println("MyRunnable");
try {
Thread.sleep(1000000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
результат операции:
main Thread begin
MyThread
Распечатываются только 2 лога, и видят только при наблюдении за потокомmain
тред, не виделMyThread
а такжеMyRunnable
Тема подтверждает то, что мы сказали выше:позвонить напрямуюrun()
метод, поток не создается.
давайте посмотрим ниже
перечислитьstart()
код:
public class ThreadImpl {
public static void main(String[] args) {
MyThread myThread = new MyThread();
myThread.setName("MyThread");
Thread myRunnable = new Thread(new MyRunnable());
myRunnable.setName("MyRunnable");
System.out.println("main Thread begin");
myThread.start();
myRunnable.start();
System.out.println("main Thread end");
try {
Thread.sleep(1000000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
результат операции:
main Thread begin
main Thread end
MyThread
MyRunnable
Все журналы распечатываются и проходятVisualVMинструменты могут видетьMyThread
а такжеMyRunnable
нить. Увидев этот результат, не забудьте создать поток для вызоваstart()
метод.
Сегодня я расскажу об этом первым и продолжу уделять внимание последующему содержанию.
推荐阅读
Самые базовые знания о потоках
Босс сказал вам перестать блокировать
Ешьте фаст-фуд, чтобы узнать последовательный, параллельный, параллелизм
Заварите чашку чая и научитесь быть асинхронным
Как много вы знаете о процессе?
Шаблоны проектирования читают и забывают, забывают и снова читают?
Ответьте на «Шаблоны проектирования» в фоновом режиме, чтобы получить электронную книгу «Одна история, один шаблон проектирования».
觉得文章有用帮忙转发&点赞,多谢朋友们!