Java
July 26, 2020

Многопоточность

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

У каждого объекта имеется свой неявный монитор, вход в который осуществляется
автоматически, когда для этого объекта вызывается синхронизированный метод.

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

В самом общем смысле для создания потока исполнения следует получить экземпляр объекта типа Thread. В языке Java этой цели можно достичь следующими двумя способами:

  • реализовав интерфейс RunnaЫe;
  • расширив класс Thread.

Реализация интерфейса Runnable

Самый простой способ создать поток исполнения состоит в том, чтобы объявить
класс, реализующий интерфейс Runnable. Этот интерфейс предоставляет
абстракцию единицы исполняемого кода. Поток исполнения можно создать из
объекта любого класса, реализующего интерфейс Runnable. Для реализации интерфейса Runnableв классе должен быть объявлен единственный метод run()

В теле метода run() определяется код, который, собственно, и составляет новый
поток исполнения. Но в методе run() можно также вызывать другие методы, использовать другие классы, объявлять переменные таким же образом, как и в главном потоке исполнения. Единственное отличие заключается в том, что в методе run() устанавливается точка входа в другой, параллельный поток исполнения в программе.

Этот поток исполнения завершится, когда метод run() возвратит управление.

После создания класса, реализующего интерфейс Runnable, в этом классе следует
получить экземпляр объекта типа Thread. Для этой цели в классе Thread
определен ряд конструкторов. Тот конструктор, который должен использоваться
в данном случае, выглядит в общей форме следующим образом:

Thread(Runnable объект_потока, String имя_потока)

В этом конструкторе параметр объектпотока обозначает экземпляр класса,
реализующего интерфейс Runnable. Этим определяется место, где начинается
выполнение потока.

После того как новый поток исполнения будет создан, он не запускается до тех
пор, пока не будет вызван метод start(), объявленный в классе Thread. По существу, в методе start() вызывается метод run().

Выбор способа создания потоков исполнения

В классе Threadопределяется ряд методов, которые могут быть переопределены в производных классах. И только один из них должен быть непременно переопределен: метод run(). Безусловно, этот метод требуется и в том случае, когда реализуется интерфейс Runnable.

Многие программирующие на Java считают, что классы следует расширять только в том случае, если они должны быть усовершенствованы или каким-то образом видоизменены. Следовательно, если ни один из других методов не переопределяется в классе Thread, то лучше и проще реализовать интерфейс Runnable. Кроме того, при реализации интерфейса Runnableкласс порождаемого потока исполнения не должен наследовать класс Thread, что освобождает его от наследования другого класса.