- Потоки. Класс Thread и интерфейс Runnable
- Создание собственного потока
- Создание потока с интерфейсом Runnable
- Ключевое слово syncronized — синхронизированные методы
- Looper
- BestProg
- Потоки выполнения. Методы класса Thread : join() , isAlive() , getPriority() , setPriority()
- Содержание
- Методы isAlive () и join () класса Thread в Java
Потоки. Класс Thread и интерфейс Runnable
В русской терминологии за термином Thread укрепился перевод «Поток». Хотя это слово также можно перевести как «Нить». Иногда в зарубежных учебных материалах понятие потока объясняется именно на нитях. Продолжим логический ряд — там где нити, там и клубок. А где клубок, там и кот. Сразу видно, что у переводчиков не было котов. Так и возникла путаница. Тем более что существуют другие потоки под термином Stream. Переводчики, вообще странный народ.
Когда запускается любое приложение, то начинает выполняться поток, называемый главным потоком (main). От него порождаются дочерние потоки. Главный поток, как правило, является последним потоком, завершающим выполнение программы.
Несмотря на то, что главный поток создаётся автоматически, им можно управлять через объект класса Thread. Для этого нужно вызвать метод currentThread(), после чего можно управлять потоком.
Класс Thread содержит несколько методов для управления потоками.
- getName() — получить имя потока
- getPriority() — получить приоритет потока
- isAlive() — определить, выполняется ли поток
- join() — ожидать завершение потока
- run() — запуск потока. В нём пишите свой код
- sleep() — приостановить поток на заданное время
- start() — запустить поток
Получим информацию о главном потоке и поменяем его имя.
Имя у главного потока по умолчанию main, которое мы заменили на CatThread.
Вызовем информацию о названии потока без указания метода.
В этом случае можно увидеть строчку Thread[main,5,main] — имя потока, его приоритет и имя его группы.
Создание собственного потока
Создать собственный поток не сложно. Достаточно наследоваться от класса Thread.
Объявим внутри нашего класса внутренний класс и вызовем его по щелчку, вызвав метод start().
Как вариант, перенести вызов метода start() в конструктор.
Создание потока с интерфейсом Runnable
Есть более сложный вариант создания потока. Для создания нового потока нужно реализовать интерфейс Runnable. Вы можете создать поток из любого объекта, реализующего интерфейс Runnable и объявить метод run().
Внутри метода run() вы размещаете код для нового потока. Этот поток завершится, когда метод вернёт управление.
Когда вы объявите новый класс с интерфейсом Runnable, вам нужно использовать конструктор:
В первом параметре указывается экземпляр класса, реализующего интерфейс. Он определяет, где начнётся выполнение потока. Во втором параметре передаётся имя потока.
После создания нового потока, его нужно запустить с помощью метода start(), который, по сути, выполняет вызов метода run().
Создадим новый поток внутри учебного проекта в виде вложенного класса и запустим его.
Внутри конструктора MyRunnable() мы создаём новый объект класса Thread
В первом параметре использовался объект this, что означает желание вызвать метод run() этого объекта. Далее вызывается метод start(), в результате чего запускается выполнение потока, начиная с метода run(). В свою очередь метод запускает цикл для нашего потока. После вызова метода start(), конструктор MyRunnable() возвращает управление приложению. Когда главный поток продолжает свою работу, он входит в свой цикл. После этого оба потока выполняются параллельно.
Можно запускать несколько потоков, а не только второй поток в дополнение к первому. Это может привести к проблемам, когда два потока пытаюсь работать с одной переменной одновременно.
Ключевое слово syncronized — синхронизированные методы
Для решения проблемы с потоками, которые могут внести путаницу, используется синхронизация.
Метод может иметь модификатор syncronized. Когда поток находится внутри синхронизированного метода, все другие потоки, которые пытаются вызвать его в том же экземпляре, должны ожидать. Это позволяет исключить путаницу, когда несколько потоков пытаются вызвать метод.
Кроме того, ключевое слово syncronized можно использовать в качестве оператора. Вы можете заключить в блок syncronized вызовы методов какого-нибудь класса:
Looper
Поток имеет в своём составе сущности Looper, Handler, MessageQueue.
Каждый поток имеет один уникальный Looper и может иметь много Handler.
Считайте Looper вспомогательным объектом потока, который управляет им. Он обрабатывает входящие сообщения, а также даёт указание потоку завершиться в нужный момент.
Поток получает свой Looper и MessageQueue через метод Looper.prepare() после запуска. Looper.prepare() идентифицирует вызывающий потк, создаёт Looper и MessageQueue и связывает поток с ними в хранилище ThreadLocal. Метод Looper.loop() следует вызывать для запуска Looper. Завершить его работу можно через метод looper.quit().
Используйте статический метод getMainLooper() для доступа к Looper главного потока:
Создадим два потока. Один запустим в основном потоке, а второй отдельно от основного. Нам будет достаточно двух кнопок и метки.
Обратите внимание, как запускаются потоки. Первый поток запускается с помощью метода start(), а второй — run(). Затем проверяем, в каком потоке мы находимся.
Эта тема достаточно сложная и для большинства не представляет интереса и необходимости изучать.
В Android потоки в чистом виде используются всё реже и реже, у системы есть собственные способы.
Источник
BestProg
Потоки выполнения. Методы класса Thread : join() , isAlive() , getPriority() , setPriority()
Перед изучением данной темы рекомендуется ознакомиться со следующими темами:
Содержание
Поиск на других ресурсах:
1. Почему нужно, чтобы основной (вызывающий) поток завершался первым? Объяснение. Метод join() . Необходимость применения, общая форма
Пусть заданы два потока:
- основной (вызывающий). Из основного потока запускается (вызывается) дочерний поток;
- дочерний (вызванный).
Для того, чтобы из дочернего потока получить результат (объект, данные), основной (вызывающий) поток должен завершаться последним. Если основной поток завершается быстрее дочернего потока, то, скорее всего, будут получаться нулевые (начальные) или промежуточные значения из дочернего потока, что является ошибкой.
Для того, чтобы основной поток завершался последним в языке Java используется метод join() . Общая форма метода следующая:
- InterruptedException – класс исключения, которое возникает, когда какой-нибудь другой поток прервал текущий поток. После возникновения этого исключения прерванный статус текущего потока сбрасывается.
2. Метод join() . Пример
Задача. Реализовать вызов дочернего потока из основного потока. В дочернем потоке определяется максимальное значение массива целых чисел. Полученный результат (максимальное значение) должен возвращаться в основной поток и выводиться на экран.
Решение. Для создания дочернего потока разрабатывается отдельный класс. В нашем случае класс имеет имя Thread1 . В этом классе объявляются все необходимые элементы:
- ссылка thr на дочерний поток типа Thread ;
- массив AI целых чисел;
- переменная maximum , которая есть результатом работы потока;
- конструктор. В конструкторе осуществляется начальная инициализация массива а также создание и запуск дочернего потока. Запуск потока выполняется методом start() . Если в конструкторе не реализовать создание и запуск дочернего потока, то методы экземпляра класса будут выполняться в основном потоке;
- метод run() , который определен в интерфейсе Runnable . Поскольку класс Thread1 реализует этот интерфейс, то в нем нужно обязательно реализовывать метод run() . В методе run() вписывается основной код решения нашей задачи — код поиска максимального значения;
- методы доступа к полям класса, значение которых используется в основном потоке.
В данной задаче основным потоком служит функция main() , в которой нужно выполнить следующие шаги:
- объявить тестируемый массив;
- создать дочерний поток (экземпляр класса Thread1 ) и получить ссылку на него;
- запустить метод join() для того, чтобы основной поток завершился последним;
- после завершения дочернего потока прочитать результат, полученный в этом потоке.
Текст работы программы следующий.
Если в функции main() убрать код
то будет получен следующий результат
Это означает, что основной поток завершается первым, не дождавшись завершения дочернего потока. В этом случае из дочернего потока возвращается первоначальное значение переменной maximum в экземпляре t1 . А это есть ошибка.
Результат выполнения программы
3. Метод isAlive() . Определить, выполняется ли поток. Пример
Метод isAlive() предназначен для определения существования (выполнения) потока. Общая форма метода следующая:
Метод возвращает true , если поток, для которого вызван метод, еще выполняется. В противном случае он возвращает false .
Пример. В примере с помощью метода isAlive() ожидается завершение дочернего потока с целью получения результата.
В дочернем потоке вычисляется сумма элементов массива чисел типа double . Чтобы получить корректную сумму, нужно чтобы главный поток завершился последним.
В вышеприведенном примере, задержка осуществляется с помощью вызова
Если закомментировать эту строку, то программа может выдать нулевое значение суммы. Это связано с тем, что главный поток завершится до завершения дочернего потока.
Результат выполнения программы
4. Методы setPriority() , getPriority() . Установить и получить приоритет потока. Пример
Как известно, для потоков выполнения может быть установлен различный приоритет. Потоки с большим приоритетом получают большую часть времени центрального процессора на свое выполнение.
В языке Java существует возможность установки приоритета потоков. Для этого используются два метода:
- setPriority() — устанавливает значение приоритета потока;
- getPriority() — читает (получает) значение приоритета потока.
В документации Java общая форма методов следующая:
- level – уровень приоритета, который задается в пределах констант от MIN_PRIORITY к MAX_PRIORITY . Значение MIN_PRIORITY = 1 значение MAX_PRIORITY = 10. Если нужно установить по умолчанию значение приоритета, то для этого используется статическая константа NORM_PRIORITY , которая равна 5.
Приклад. В примере демонстрируется создание трех потоков с различными приоритетами. В каждом потоке создается массив случайных целых чисел. Для инкапсуляции потока реализован класс RandomArray , который содержит следующие составляющие:
- внутреннее поле thr — ссылка на текущий поток выполнения;
- внутреннее поле AI — ссылка на массив чисел;
- конструктор RandomArray() . В конструкторе задается приоритет потока и осуществляется запуск потока на выполнение;
- метод run() , в котором генерируется массив случайных чисел. Этот метод является точкой входа в поток;
- методы доступа к внутренним полям getThread() и getArray() ;
- метод getPriority() , который возвращает приоритет потока выполнения. Этот метод обращается к одноименному методу экземпляра thr для получения числового значения приоритета.
Источник
Методы isAlive () и join () класса Thread в Java
Как один поток может узнать, когда закончился другой поток?
Тема предоставляет средства, с помощью которых вы можете ответить на этот вопрос. Многопоточность Java предоставляет два способа найти
- isAlive (): проверяет, жив ли этот поток. Поток жив, если он был запущен и еще не умер. Существует переходный период от того, когда поток работает, до того, когда поток не работает. После возврата из метода run () поток останавливается в течение короткого периода времени. Если мы хотим знать, был ли вызван метод start потока или был ли поток завершен, мы должны использовать метод isAlive (). Этот метод используется, чтобы узнать, был ли поток действительно запущен и еще не завершен.
Общий синтаксис:
join (): Когда вызывается метод join (), текущий поток просто будет ждать, пока поток, с которым он соединяется, больше не является живым.
Или мы можем сказать, что метод, который вы будете чаще использовать для ожидания завершения потока, называется join (). Этот метод ожидает завершения потока, в котором он вызывается. Его имя происходит от концепции вызывающего потока, ожидающего, пока указанный поток не присоединится к нему. Дополнительные формы join () позволяют вам указать максимальное количество времени ожидания завершения указанного потока.
Синтаксис:
Вот улучшенная версия предыдущего примера, которая использует join (), чтобы гарантировать, что основной поток остановится последним. Он также демонстрирует метод isAlive ().
// Java-программа для иллюстрации
// является живым()
public class oneThread extends Thread <
public void run()
catch (InterruptedException ie) <
public static void main(String[] args)
oneThread c1 = new oneThread();
oneThread c2 = new oneThread();
Пример потока без объединения ()
// Java-программа для иллюстрации
// поток без join ()
public class oneThread extends Thread <
public void run()
catch (InterruptedException ie) <
public static void main(String[] args)
oneThread c1 = new oneThread();
oneThread c2 = new oneThread();
Пример потока с join ()
// Java-программа для иллюстрации
public class oneThread extends Thread <
public void run()
catch (InterruptedException ie) <
public static void main(String[] args)
oneThread c1 = new oneThread();
oneThread c2 = new oneThread();
c1.join(); // Ожидание завершения c1
catch (InterruptedException ie) <
Эта статья предоставлена Shivani Ghughtyal . Если вы как GeeksforGeeks и хотели бы внести свой вклад, вы также можете написать статью с помощью contribute.geeksforgeeks.org или по почте статьи contribute@geeksforgeeks.org. Смотрите свою статью, появляющуюся на главной странице GeeksforGeeks, и помогите другим вундеркиндам.
Пожалуйста, пишите комментарии, если вы обнаружите что-то неправильное, или вы хотите поделиться дополнительной информацией по обсуждаемой выше теме.
Источник