Самые базовые знания о потоках

Java

Статья 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()метод.

Сегодня я расскажу об этом первым и продолжу уделять внимание последующему содержанию.

推荐阅读

Самые базовые знания о потоках

Босс сказал вам перестать блокировать

Ешьте фаст-фуд, чтобы узнать последовательный, параллельный, параллелизм

Заварите чашку чая и научитесь быть асинхронным

Как много вы знаете о процессе?

Шаблоны проектирования читают и забывают, забывают и снова читают?

Ответьте на «Шаблоны проектирования» в фоновом режиме, чтобы получить электронную книгу «Одна история, один шаблон проектирования».

觉得文章有用帮忙转发&点赞,多谢朋友们!

LieBrother