В этом блоге мы поймем, что такое многопоточность, как она работает в Java и почему так важно ее понимать, а также различные важные концепции, связанные с ней.
Что такое поток?
Поток — это очень легкая и самая маленькая часть процесса, которая позволяет программе работать более эффективно, выполняя несколько задач одновременно.
Что такое многопоточность?
Многопоточность — это функция Java, которая относится к процессу одновременного запуска двух или более потоков для максимальной эффективности ЦП.
Жизненный цикл потока
В своем жизненном цикле нить проходит различные этапы. Поток, например, рождается, запускается, выполняется и затем умирает. На следующей диаграмме показан весь жизненный цикл потока.
Новинка. В этом разделе цепочка создается с использованием класса Thread. Он остается в этом состоянии до тех пор, пока программа не запустит поток. его также называют рожденной нитью.
Runnable: в этом состоянии экземпляр потока вызывается методом запуска. Управление потоком передается компьютерному оборудованию для завершения выполнения. Это зависит от аппаратного обеспечения компьютера и от того, следует ли запускать поток.
Выполняется. Как только поток начинает выполняться, его состояние изменяется на «выполняется». Аппаратное обеспечение компьютера выбирает один поток из пула потоков, и он начинает выполняться в приложении.
Ожидание: это может быть состояние, в котором поток должен ожидать. Поскольку их модуль многопоточности работает внутри приложения, существует потребность в синхронизации между потоками. Следовательно, один поток должен ждать, пока не будет выполнен другой поток. Так что это состояние называется состоянием ожидания.
Dead: это может быть состояние после завершения потока. Поток находится в рабочем состоянии, и как только он завершает процесс, он находится в «мертвом состоянии».
Как создать поток в Java?
В Java Multithreading вы можете создать поток двумя способами:
- Расширяя класс Thread
Класс Thread предоставляет конструкторы и методы для создания и выполнения операций над потоком. Класс Thread расширяет класс Object и реализует интерфейс Runnable.
2. Реализуя интерфейс Runnable
Интерфейс Runnable должен быть реализован любым классом, экземпляры которого предназначены для выполнения потоком. Интерфейс Runnable имеет только один метод с именем run().
Часто используемые методы класса Thread:
public void run(): используется для выполнения действия для потока.
public void start(): запускает выполнение потока. JVM вызывает метод run() в потоке.
public void sleep(long milseconds): переводит выполняемый в данный момент поток в спящий режим (временно прекращает выполнение) на указанное количество миллисекунд.
public void join(): ожидает завершения потока.
public void join (длинные миллисекунды): ожидает завершения потока в течение указанных миллисекунд.
public int getPriority(): возвращает приоритет потока.
public int setPriority(int priority): изменяет приоритет потока.
public String getName(): возвращает имя потока.
public void setName(String name): изменяет имя потока.
public Thread currentThread(): возвращает ссылку на исполняемый в данный момент поток.
public int getId(): возвращает идентификатор потока.
public Thread.State getState(): возвращает состояние потока.
public boolean isAlive(): проверяет, жив ли поток.
public void yield(): временно приостанавливает текущий исполняемый объект потока и позволяет другим потокам выполняться.
public void suspend(): используется для приостановки потока (устарело).
public void возобновление(): используется для возобновления приостановленного потока (устарело).
public void stop(): используется для остановки потока (устарело).
public boolean isDaemon(): проверяет, является ли поток потоком демона.
public void setDaemon(boolean b): помечает поток как демон или пользовательский поток.
public void interrupt(): прерывает поток.
public boolean isInterrupted(): проверяет, был ли поток прерван.
public static boolean interrupted(): проверяет, был ли текущий поток прерван.
Приоритет потока (Thread Priority):
Каждому потоку назначается приоритет. Приоритеты представлены целыми числами от 1 до 10. В основном планировщик потоков планирует потоки в соответствии с их приоритетом, но это не гарантируется, поскольку это зависит от спецификации виртуальной машины Java, которую он выбирает.
public final int getPriority(): Метод java.lang.Thread.getPriority() возвращает приоритет предоставленного потока (метод получения приоритета потока).
public final void setPriority(int newPriority): Метод java.lang.Thread.setPriority() используется для присвоения приоритета потоку newPriority(метод установки приоритета потока).
Поток демона в Java:
Демонический поток в Java – это поток поставщика услуг, предоставляющий услуги пользовательскому потоку. Его жизненный цикл зависит от пользовательских потоков, т.е. когда все пользовательские потоки умирают, JVM автоматически завершает этот поток.
Примеры автоматически запускаемых потоков Java-демона, например. gc, финализатор и т. д.
Что нужно помнить для Daemon Thread в Java
- используется для предоставления услуг пользовательским потокам только для фоновых задач поддержки.
- жизненный цикл зависит от пользовательских потоков.
- Приоритет этих потоков низкий.
Планировщик потоков в Java:
Компонент Java, который решает, какой поток запустить или выполнить, а какой ожидать, называется планировщиком потоков в Java. В Java, если поток находится в рабочем состоянии, планировщик потоков выбирает только его. Однако, если в рабочем состоянии находится более одного потока, планировщик потоков должен выбрать один из потоков и проигнорировать другие. Планирование потока зависит от двух факторов: Приоритет и Время прибытия.
Приоритет. Приоритет темы обсуждался ранее. Поток с более высоким приоритетом имеет больше шансов быть выбранным планировщиком потоков.
Время прибытия. Предположим, что два потока с одинаковым приоритетом переходят в состояние готовности к выполнению, тогда только приоритет не может решить, какой поток выбрать . В таких случаях планировщик потоков учитывает время прибытия потока. Поток, прибывший первым, получает преимущество перед другими потоками.
Алгоритмы планировщика потоков:
1. Планирование обслуживания в порядке очереди
2. Планирование с разделением по времени
3. Упреждающее планирование
Сборка мусора Java:
В Java мусор относится к объектам, на которые нет ссылок.
Сборка мусора — это процесс автоматического освобождения неиспользуемой памяти во время выполнения.
Преимущества сбора мусора
- Это делает java эффективным с точки зрения использования памяти, поскольку сборка мусора удаляет объекты, на которые нет ссылок, из кучи памяти.
- Нет необходимости прилагать дополнительные усилия, так как это автоматически выполняется сборщиком мусора (частью JVM).
Как объект может быть без ссылки?
- Обнуление ссылки
- Присвоение ссылки другому
- По анонимному объекту и т.д.
Синхронизация в Java
Синхронизация — это возможность контролировать доступ нескольких потоков к любому общему ресурсу.
Синхронизация Java — лучший вариант, когда мы хотим разрешить только одному потоку доступ к общему ресурсу.
Зачем использовать синхронизацию?
- Чтобы избежать помех нити.
- Чтобы избежать/предотвратить проблему согласованности.
Типы синхронизации
- Синхронизация процессов
- Синхронизация потоков
Существует два типа синхронизации потоков:
- Взаимный эксклюзив
- Синхронный метод.
- Синхронизированный блок.
- Статическая синхронизация.
- Сотрудничество (межпотоковое взаимодействие в java)
Тупик в Java
Взаимоблокировки являются частью многопоточности в java. Тупик может возникнуть, когда поток ожидает блокировки объекта, полученной другим потоком, а второй поток ожидает блокировки объекта, полученной первым потоком. Поскольку оба потока ждут друг друга, чтобы снять блокировку, такое состояние называется взаимоблокировкой.
Как избежать взаимоблокировки в Java?
Тупики не могут быть полностью разрешены. Но мы можем избежать их, следуя основным правилам, упомянутым ниже:
- Избегайте вложенных блокировок. Избегайте блокировки нескольких потоков, это основная причина взаимоблокировки.
- Избегайте ненужных блокировок
- Использование объединения потоков. Взаимная блокировка обычно возникает, когда один поток ожидает завершения другого. В этом случае мы можем использовать join с максимальным временем, которое займет поток.
Межпотоковое взаимодействие в Java
Взаимодействие между потоками или Взаимодействие — это взаимодействие синхронизированных потоков друг с другом.
Сотрудничество (межпотоковое взаимодействие) — это метод, при котором работа потока в его критической секции приостанавливается, а другому потоку разрешается войти (или заблокироваться) в той же критической секции для выполнения. Это реализуется следующими методами класса Object:
- ждать()
- поставить в известность()
- уведомить всех ()
1) метод ожидания()
Метод wait() заставляет текущий поток снимать блокировку и ждать, пока другой поток не вызовет метод notify() или метод notifyAll() для этого объекта, или пока не истечет указанное количество времени.
Текущий поток должен владеть монитором этого объекта, поэтому он должен вызываться только из синхронизированного метода, иначе он выдаст исключение.
2) метод уведомления()
Метод notify() пробуждает один поток, ожидающий на мониторе этого объекта. Если на этом объекте ожидают какие-либо потоки, один из них выбирается для пробуждения. Выбор произвольный и происходит на усмотрение реализации.
3) метод уведомить всех ()
Пробуждает все потоки, ожидающие на мониторе этого объекта.
Прерывание потока:
Если какой-либо поток находится в спящем или ожидающем состоянии, вызов метода interrupt() в потоке выводит из спящего или ожидающего состояния, вызывая InterruptedException. Если поток не находится в состоянии ожидания или ожидания, вызов метода interrupt() ведет себя нормально и не прерывает поток, а устанавливает флаг прерывания в значение true. Давайте сначала посмотрим на методы, предоставляемые классом Thread для прерывания потока.
3 метода класса Thread для прерывания потока
- public void interrupt()
- public static boolean interrupted()
- public boolean isInterrupted()
Преимущества многопоточности в Java:
- Сокращение времени разработки за счет повышения производительности за счет
- Упрощенное и оптимизированное кодирование программ
- Импровизированная отзывчивость графического интерфейса
- Одновременное и параллельное возникновение задач
- Лучшее использование хранилища кеша за счет использования ресурсов
- Снижение затрат на техническое обслуживание
- Лучшее использование ресурсов ЦП
Недостатки многопоточности в Java:
- Сложные процессы отладки и тестирования
- Накладное переключение контекста
- Повышенная вероятность возникновения взаимоблокировок
- Повышенный уровень сложности при написании программы
- Непредсказуемые результаты
Заключение
В целом, многопоточность в Java — важная концепция, о которой должен знать каждый разработчик Java. Это помогает сделать программу эффективной и сократить использование ресурсов хранения. Это фактически заставляет процессоры использоваться оптимально, чтобы работать хорошо, независимо от их сложности. Если вы хотите больше узнать о потоках, вы должны понимать класс Thread и интерфейс Runnable, поскольку оба они предлагают путь и делают его популярным среди разработчиков.
Ссылки
- Хуо Ян Чен, «Анализ потенциальных тупиков в многопоточных объектно-ориентированных программах на Java», Международная конференция IEEE по системам, человеку и кибернетике, 2005 г., 2005 г.
- Мурарка, Паван и Реза, Мотахар и Панда, Рама Ранджан. (2014). Анализ многопоточности в Java для символьных вычислений на многоядерных процессорах.
- https://www.javatpoint.com/multithreading-in-java
- https://www.geeksforgeeks.org/multithreading-in-java/