1. Обзор темы
Потоки — это базовая исполнительная единица выполнения программы. Когда операционная система (за исключением однопоточных операционных систем, таких как ранняя версия DOS от Microsoft) выполняет программу, в системе устанавливается процесс, и в этом процессе должен быть установлен хотя бы один поток (этот поток называется основным). thread) thread) в качестве точки входа для запуска этой программы. Следовательно, любая программа, работающая в операционной системе, имеет хотя бы один основной поток.
Процессы и потоки — две основные операционные модели в современных операционных системах. В операционной системе может быть несколько процессов, включая системные процессы (процессы, созданные внутри операционной системы) и пользовательские процессы (процессы, созданные пользовательскими программами); Между процессами нет общей памяти, а это означает, что процессы в системе выполняются в своих собственных независимых пространствах памяти. Потоки в процессе могут совместно использовать пространство памяти, выделенное системой для процесса.
Потоки могут не только совместно использовать память процесса, но и иметь собственное пространство памяти. Это пространство памяти также называется стеком потока. Оно выделяется системой при создании потока. Оно в основном используется для сохранения. данные, используемые внутри потока, такие как стек потока. Переменные, определенные в функции выполнения.
Примечание. Любой поток выполняет функцию при его создании. Эта функция называется функцией выполнения потока. Эту функцию также можно рассматривать как точку входа в поток (аналогично основной функции в программе). Независимо от того, какой язык или технология используется для создания потока, эта функция должна быть выполнена (выражение этой функции может быть разным, но такая функция всегда будет). Например, третий параметр API-функции CreateThread, используемой для создания потока в Windows, — это указатель на эту исполняющую функцию.
После того как операционная система разделяет процесс на несколько потоков, эти потоки могут выполняться одновременно под управлением операционной системы, что значительно повышает эффективность работы программы. Хотя с точки зрения макроса выполнение потоков выглядит как одновременное выполнение нескольких потоков, на самом деле это всего лишь прикрытие операционной системы. Поскольку ЦП может выполнять только одну инструкцию за раз, невозможно одновременно выполнять две задачи на компьютере с одним ЦП. Чтобы повысить эффективность работы программы, операционная система удаляет поток, когда он простаивает, и позволяет другим потокам выполнять его. Этот метод называется планированием потоков. Причина, по которой мы видим одновременное выполнение нескольких потоков на поверхности, заключается в том, что время переключения между разными потоками очень короткое, а в нормальных обстоятельствах переключение происходит очень часто. Предположим, у нас есть потоки A и B. Во время выполнения может случиться так, что после того, как A выполняется в течение 1 миллисекунды, после переключения на B, B выполняется еще 1 миллисекунду, затем переключается на A, и A выполняется еще 1 миллисекунду. Поскольку 1 миллисекунда сложна для восприятия обычным людям, на первый взгляд кажется, что A и B выполняются одновременно, но на самом деле A и B выполняются попеременно.
2. Польза, которую нам приносят треды
Правильное использование потоков может снизить затраты на разработку и обслуживание и даже повысить производительность сложных приложений. Например, в приложениях с графическим интерфейсом события могут лучше обрабатываться за счет асинхронной природы потоков; в программах сервера приложений можно создать несколько потоков для обработки клиентских запросов. Потоки могут даже упростить реализацию виртуальных машин. Например, сборщик мусора виртуальной машины Java (JVM) обычно работает в одном или нескольких потоках. Таким образом, использование потоков улучшит наши приложения в следующих пяти аспектах:
1. Полностью используйте ресурсы процессора.
Большинство компьютеров в мире сейчас имеют только один процессор. Поэтому особенно важно полностью использовать ресурсы ЦП. При выполнении однопоточной программы процессор может простаивать, пока программа заблокирована. Это приведет к большой трате вычислительных ресурсов. Использование многопоточности в программе может запускать другие потоки, когда поток находится в режиме ожидания или заблокирован, а процессор простаивает. Таким образом, процессору трудно простаивать. Таким образом, ресурсы процессора используются полностью.
2. Упростите модель программирования.
Если программа выполняет только одну задачу, то просто напишите однопоточную программу и напишите код в соответствии с этапами выполнения задачи. Но для выполнения нескольких задач, если вы по-прежнему используете один поток, вам необходимо определить в программе, должна ли и когда выполняться каждая задача. Например, он отображает часы, минуты и секунды часов. Если вы используете одну нить, вам придется оценивать время вращения и угол этих трех указателей один за другим в цикле. Если для обработки отображения этих трёх указателей используются три потока, то это означает выполнение отдельной задачи для каждого потока. Это помогает разработчикам понимать и поддерживать программу.
3. Упростите обработку асинхронных событий.
Когда серверное приложение получает разные клиентские соединения, самый простой способ справиться с этим — создать поток для каждого клиентского соединения. В этом случае поток прослушивания по-прежнему отвечает за прослушивание запросов от клиента. Если приложение такого типа обрабатывается одним потоком, то, когда прослушивающий поток получает запрос клиента, он начинает читать данные, отправленные клиентом. После чтения данных метод чтения блокируется, то есть этот поток. больше не сможет слушать запросы клиентов. Если вы хотите обрабатывать несколько клиентских запросов в одном потоке, вы должны использовать неблокирующие соединения Socket и асинхронный ввод-вывод. Однако использование асинхронного ввода-вывода сложнее контролировать и более подвержено ошибкам, чем использование синхронного ввода-вывода. Таким образом, асинхронные события, такие как множественные запросы, можно легче обрабатывать с помощью многопоточности и синхронного ввода-вывода.
4. Сделайте графический интерфейс более эффективным
При использовании одного потока для обработки событий графического интерфейса необходимо использовать цикл для сканирования событий графического интерфейса, которые могут произойти в любой момент. В цикле, помимо сканирования событий графического интерфейса, должны выполняться другие программные коды. Если код слишком длинный, события графического интерфейса будут «заморожены» до тех пор, пока код не будет выполнен.
В современных средах графического пользовательского интерфейса (таких как SWING, AWT и SWT) для сканирования событий графического пользовательского интерфейса используется отдельный поток диспетчеризации событий (EDT). Когда мы нажимаем кнопку, в этом потоке диспетчеризации событий вызывается функция события нажатия кнопки. Поскольку задачей EDT является только сканирование событий GUI, реакция на события таким образом происходит очень быстро.
5. Экономия затрат
Обычно существует три метода повышения эффективности выполнения программы:
(1) Увеличьте количество процессоров в компьютере.
(2) Запустите несколько процессов для одной программы.
(3) Используйте несколько процессов в программе.
Первый способ самый простой, но и самый дорогой. Этот метод не требует модификации программы. Теоретически любая программа может использовать этот метод для повышения эффективности выполнения. Хотя второй метод не требует покупки нового оборудования, совместное использование данных непросто. Если задача, которую должна выполнить эта программа, требует совместного использования данных, этот метод неудобен, и запуск нескольких потоков будет потреблять много ресурсов системы. ресурсы. Третий метод лишь компенсирует недостатки первого метода, унаследовав при этом его преимущества. Другими словами, нет необходимости приобретать процессор, и он не будет занимать много системных ресурсов, запуская слишком много потоков (по умолчанию объем памяти, занимаемый потоком, намного меньше, чем объем памяти, занимаемый процессом) . Multiple), а многопоточность может имитировать режим работы нескольких процессоров. Поэтому использование многопоточности — самый дешевый способ повысить эффективность выполнения программы.
3. Модель потоков Java
Поскольку Java является чисто объектно-ориентированным языком, модель потоков Java также является объектно-ориентированной. Java инкапсулирует все необходимые функции потоков через класс Thread. Чтобы создать поток, должна существовать функция выполнения потока. Эта функция выполнения потока соответствует методу run класса Thread. Класс Thread также имеет метод start, отвечающий за создание потока, что эквивалентно вызову функции создания потока Windows CreateThread. При вызове метода start, если поток успешно установлен, автоматически вызывается метод run класса Thread. Таким образом, любой класс Java, наследующий Thread, может создать поток с помощью метода start класса Thread. Если вы хотите запустить собственную функцию выполнения потока, вам необходимо переопределить метод run класса Thread.
В дополнение к классу Thread в модели потока Java существует также интерфейс Runnable, который определяет, может ли класс Java использоваться в качестве класса потока. Этот интерфейс имеет только один абстрактный метод run, который является функцией выполнения потока Java. модель резьбы. Следовательно, единственным критерием для класса потока является то, реализует ли этот класс метод run интерфейса Runnable. Другими словами, класс с функцией выполнения потока является классом потока.
Как видно из вышеизложенного, существует два способа создания потоков в Java: один — наследовать класс Thread, а другой — реализовать интерфейс Runnable и создавать потоки через Thread и класс, реализующий Runnable. эти два метода по сути являются методом, то есть поток создается через класс Thread и запускается метод run. Но их большое отличие состоит в том, что потоки создаются путем наследования класса Thread. Хотя это проще реализовать, поскольку Java не поддерживает множественное наследование, если этот класс потока наследует Thread, он не может наследовать другие классы. Поэтому модель потоков Java обеспечивает. методы для создания потоков путем реализации интерфейса Runnable, чтобы классы потоков могли при необходимости наследовать бизнес-классы вместо класса Thread.