Глубокое погружение в виртуальный поток — от внутренней реализации к антишаблонам

Меня зовут Хаясака, я веб-инженер. Эта статья была опубликована в ноябре 2025 года. JJUG CCC 2025 Осень В этой статье обобщается презентация «Глубокое погружение в виртуальную нить». Ниже мы объясним виртуальный поток Java, его внутреннюю реализацию и моменты, на которые следует обратить внимание при его использовании. Слайды презентации Колонка динамиков Вы можете просмотреть его здесь.

Основные понятия виртуального потока

Virtual Thread — это облегченный поток, который был официально представлен в Java 21 и хорошо известен своими характеристиками, такими как «улучшение пропускной способности за счет эффективного использования времени ожидания ввода-вывода» и «поскольку он легкий, его можно генерировать в больших количествах». Например, многие из вас, возможно, видели следующую диаграмму.

Виртуальный поток (VT) монтируется на несущем потоке (CT) уровня ОС для выполнения обработки по мере необходимости. При возникновении ожидания ввода-вывода ТН сначала отсоединяется от ТТ. Во время размонтирования CT может монтировать другие виртуальные трансформаторы, что позволяет лучше использовать ресурсы в период ожидания. После завершения обработки ввода-вывода ТН снова монтируется на ТТ, и обработка возобновляется.

Однако мало что известно о внутренних деталях того, как реализован этот механизм, как обнаруживаются ожидания ввода-вывода и как сохраняется и восстанавливается стек. Поэтому в этой статье мы продолжим объяснение в форме глубокого погружения, отвечая на следующие вопросы.

  • Есть ли проблема с потреблением памяти при генерации большого объёма?
  • Как возобновить прерванную обработку?
  • Как виртуальный поток обнаруживает ожидания ввода-вывода?
  • Сколько существует несущих потоков?
  • Будет ли он прилипать к несущей нити и его нельзя будет отклеить?
  • Можно ли использовать ThreadLocal?

Механизм установки/размонтирования виртуальной резьбы

Обзор пространства памяти Java

Чтобы узнать ответ на вопрос «Является ли потребление памяти проблемой при создании большого количества файлов?», вам сначала необходимо понять пространство памяти Java.

Read more:  В отличие от предыдущего национального автомобиля, это то, что отличает I2C

Пространство памяти Java

Пространство памяти Java грубо разделено на область кучи и область стека. В области кучи,new Фактический объект сохраняется. С другой стороны, по умолчанию для каждого потока ОС зарезервировано 1 МБ области стека, а внутри хранится кадр стека.

Использование памяти потока платформы

Использование памяти потока платформы

Далее давайте посмотрим, как традиционные потоки платформы (потоки ОС) используют память. Один поток ОС имеет соответствующий Thread Существует экземпляр класса, который сам существует в куче. Этот экземпляр имеетstart() метаданные, такие как идентификатор и имя потока, а также карта ThreadLocals. С другой стороны, область стека хранит кадры стека потоков ОС, как упоминалось выше.

Оказывается, нереально сгенерировать миллионы потоков платформы, чтобы обеспечить 1 МБ стекового пространства на каждый поток. Кроме того, поскольку в стеке хранятся только ссылки, а не сами объекты, фактическая скорость использования области стека невелика, и даже если выделяется 1 МБ, большая часть его часто не используется. Таким образом, эффективность использования памяти не очень хорошая.

Использование памяти виртуального потока

Использование памяти виртуального потока

С другой стороны, а как насчет Virtual Thread? На рисунке выше показан виртуальный поток, установленный на несущем потоке. Как и в случае с потоком платформы, экземпляры виртуального потока существуют в куче, а кадры стека хранятся в области стека. Хотя кадр стека виртуального потока монтируется в несущем потоке, он использует область стека, зарезервированную для этого несущего потока, как свою собственную область.

Сохранение стека при размонтировании

Как сохранить стек при размонтировании

Теперь давайте рассмотрим ситуацию, когда виртуальный поток размонтирован из-за ожидания ввода-вывода. Текущее пространство стека должно быть освобождено, прежде чем следующий виртуальный поток сможет использовать тот же поток-носитель. Однако простая очистка этой области стека приводит к потере кадров стека времени выполнения и невозможности перезапустить исходный виртуальный поток после завершения ввода-вывода. Так что же нам делать?

Read more:  если вы видите этот цвет, он скрывает скрытую и очень практичную функциональность.

Сохранять состояние стека в куче при размонтировании

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

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

Таким образом, после завершения эвакуации вы можете повторно использовать кадр стека другого виртуального потока, поместив его в ту же область стека.

Снова смонтируйте исходный виртуальный поток после возврата результатов ввода-вывода.

Когда результат ввода-вывода возвращается и исходный виртуальный поток снова монтируется, процесс можно возобновить, скопировав стек, сохраненный в куче, в область стека несущего потока и восстановив его.

Управление стеком с продолжением

До сих пор я объяснял это с помощью диаграмм, но давайте углубимся и посмотрим на реальный исходный код JDK.Определение класса виртуального потока Вот отрывок.

final class VirtualThread extends BaseVirtualThread {
    // 中略
    private final Executor scheduler;
    // 中略
    private volatile int state;
    // 中略
    private final Continuation cont;
}

Класс виртуального потокаThreadПоскольку он наследуется от класса, переменные-члены, которые имеет Thread, например.ThreadLocalMapОн также содержит переменные-члены, такие как . одна из его переменных-членовContinuation Есть. Что это такое? на самом деле выполнение Давайте посмотрим.

public class Continuation {
    // 中略
    private StackChunk tail;
    // 中略
    private volatile boolean mounted;
    // 中略
    private Object[] scopedValueCache;
}

На самом деле, это Continuation Это и есть истинная сущность «сохраненного и экспортированного кадра стека», который фигурировал в объяснении ранее. этого класса StackChunk Переменная-член содержит фактические данные стека. более того StackChunk из выполнение Давайте следовать.

public final class StackChunk {
    // 中略
    private StackChunk parent;
    // 実際のスタックデータも保持する
}

Как видно из кода, он имеет структуру связанного списка. Другими словами,StackChunk В этой реализации вместо одновременной записи всего стека в память он разделяется на более мелкие фрагменты и используется как связанные списки.

Read more:  Смотреть: Премьер-министр Японии Санаэ Такаичи подпрыгивает от волнения на сцене, когда Трамп представляет ее в Токио

2026-03-26 02:30:00


1774520021
#Глубокое #погружение #виртуальный #поток #от #внутренней #реализации #антишаблонам

По теме

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.