Когда запускается любое приложение, то начинает выполняться поток, называемый главным потоком (main). От него порождаются дочерние потоки. Главный поток, как правило, является последним потоком, завершающим выполнение программы.
Потоки — средство, которое помогает организовать одновременное выполнение нескольких задач, каждой в независимом потоке. Потоки представляют собой экземпляры классов, каждый из которых запускается и функционирует самостоятельно, автономно (или относительно автономно) от главного поток. Хочу еще разграничить два понятия – поток и процесс. Процесс – это задача операционной системы. У него собственное адресное пространство. С ним может быть проассоциировано несколько потоков. Поток же – это гораздо более мелкая единица. Все потоки разделяют адресное пространство породившего их процесса и имеют доступ к одним данным.
1. Параллелизм и потоки вПараллелизм и потоки в
JavaJava
For students of universityFor students of university
Author: Oxana DudnikAuthor: Oxana Dudnik
2.
3.
4.
5. Создание потокаСоздание потока
Существует два способа:Существует два способа:
реализацией интерфейсареализацией интерфейса RunnableRunnable;;
class MyClass implements Runnable {class MyClass implements Runnable {
public void run() {public void run() {
// тело метода// тело метода runrun
}}
}}
наследованием классанаследованием класса ThreadThread..
class MyClass extends Thread {class MyClass extends Thread {
public void run() {public void run() {
// тело метода// тело метода runrun()()
}}
}}
6. Запуск потокаЗапуск потока
Пришло время запустить поток. Это настолькоПришло время запустить поток. Это настолько
просто, что врядли заслуживает отдельногопросто, что врядли заслуживает отдельного
раздела:раздела:
t.start();t.start();
Что происходит после старта потока? АЧто происходит после старта потока? А
происходит следующее:происходит следующее:
Стартует новый поток выполнения (с новымСтартует новый поток выполнения (с новым
стэком вызовов).стэком вызовов).
Поток переходит из состояния new (новый) вПоток переходит из состояния new (новый) в
состояние работоспособный (runnable).состояние работоспособный (runnable).
Когда поток получает шанс выполниться, онКогда поток получает шанс выполниться, он
вызывает метод run().вызывает метод run().
7. Планировщик потоковПланировщик потоков
Планировщик потоков является частьюПланировщик потоков является частью
JVM (хотя некоторые JVM мапят Java-JVM (хотя некоторые JVM мапят Java-
потоки на нативные потоки ОС) ипотоки на нативные потоки ОС) и
решает какой поток будет работать врешает какой поток будет работать в
определенный момент.определенный момент.
Любой поток, имеющий состояниеЛюбой поток, имеющий состояние
runnable (работоспособный), может бытьrunnable (работоспособный), может быть
выбран планировщиком длявыбран планировщиком для
выполнения.выполнения.
9. Управление выполнениемУправление выполнением
потоковпотоков
sleepsleep((long millislong millis);); - задает задержку в- задает задержку в
миллисекундах;миллисекундах;
sleepsleep((long millislong millis,, int nanosint nanos)) – задает задержку в– задает задержку в
миллисекундах и наносекундах.миллисекундах и наносекундах.
Приостановка потока, с передачей управленияПриостановка потока, с передачей управления
другому потоку производится статическимдругому потоку производится статическим
методомметодом yieldyield().().
Прервать работу выполняемого потока можно сПрервать работу выполняемого потока можно с
помощью методапомощью метода interruptinterrupt().().
Чтобы определить состояние потокаЧтобы определить состояние потока
используется методиспользуется метод isAliveisAlive().().
Иногда, для выполнения потока необходимоИногда, для выполнения потока необходимо
дождаться завершения другого потока. В этихдождаться завершения другого потока. В этих
случаях вам поможет методслучаях вам поможет метод joinjoin().().
10. start(). Запускает поток на
выполнение.
stop(). Заканчивает выполнение
потока.
sleep(long msec). Останавливает
выполнение потока на указанное
количество миллисекунд.
yield(). Передает ресурсов процессора
другому потоку.
suspend(). Приостанавливает
выполнение потока.
resume(). Возобновляет выполнение
потока.
13. Synchronized methodSynchronized method
public synchronized voidpublic synchronized void
someMethod(){ // code }someMethod(){ // code }
... полностью эквивалентно... полностью эквивалентно
следующей конструкции:следующей конструкции:
public voidpublic void someMethod()someMethod()
{{ synchronizedsynchronized((thisthis){ // code } }){ // code } }
14. Synchronized classSynchronized class
public classpublic class SomeClass{SomeClass{ public staticpublic static
synchronized voidsynchronized void someMethod(){someMethod(){
//code }//code }
}}
. эквивалентно:. эквивалентно:
public classpublic class SomeClass{SomeClass{ public staticpublic static
voidvoid someMethod()someMethod()
{{ synchronizedsynchronized(SomeClass.(SomeClass.classclass){){
//code } }//code } }
}}
15. Взаимные блокировки,Взаимные блокировки, deadlocksdeadlocks
Что такое взаимная блокировка по своейЧто такое взаимная блокировка по своей
сути? Все достаточно просто.сути? Все достаточно просто.
Предположим, что один поток ужеПредположим, что один поток уже
захватил монитор на некотором объектезахватил монитор на некотором объекте
x и для продолжения работы ему нужноx и для продолжения работы ему нужно
захватить монитор на объекте y.захватить монитор на объекте y.
В другом же потоке ситуация ровноВ другом же потоке ситуация ровно
обратная – он уже захватил монитор наобратная – он уже захватил монитор на
объекте y и ему нужен монитор объектаобъекте y и ему нужен монитор объекта
x.x.
В результате оба потока будут ждать,В результате оба потока будут ждать,
пока нужный монитор освободится. Какпока нужный монитор освободится. Как
вы сами прекрасно понимаете, ждатьвы сами прекрасно понимаете, ждать
они будут до бесконечности.они будут до бесконечности.
Эта ситуация и называетсяЭта ситуация и называется взаимнойвзаимной
блокировкойблокировкой –– deadlockdeadlock..
16.
17.
18. Перечислите известные Вам способыПеречислите известные Вам способы
1)избежать 2)побороть возникшие1)избежать 2)побороть возникшие
deadlock-и (представьте, что вы пишетеdeadlock-и (представьте, что вы пишете
ядро RDBMS).ядро RDBMS).
Чтобы избежать дедлоков -Чтобы избежать дедлоков -
Захватывать везде ресурсы в одинаковомЗахватывать везде ресурсы в одинаковом
порядкепорядке
или знать заранее какие ресурсы в какомили знать заранее какие ресурсы в каком
порядке будут захвачены — строить графпорядке будут захвачены — строить граф
переходов м-ду состояниямипереходов м-ду состояниями
Чтобы побороть дедлокЧтобы побороть дедлок
использовать тул для детекта заблокированныхиспользовать тул для детекта заблокированных
потоковпотоков
использовать эвристику вида — убивать одиниспользовать эвристику вида — убивать один
из двух потоков если оба взаимно блокируютиз двух потоков если оба взаимно блокируют
друг друга. например можно поделить потокидруг друга. например можно поделить потоки
на молодые и старые. более молодые потокина молодые и старые. более молодые потоки
можно убивать при обнаружении что онможно убивать при обнаружении что он
пытается захватить ресурс используемый болеепытается захватить ресурс используемый более
старым потоком.старым потоком.
19. StarvationStarvation
Название starvation полностью соответствуетНазвание starvation полностью соответствует
проблеме. Когда множество потоков постояннопроблеме. Когда множество потоков постоянно
находятся в борьбе за один критическийнаходятся в борьбе за один критический
ресурс, то все ждут, пока кто-то одинресурс, то все ждут, пока кто-то один
освободит этот ресурс. Потом из ждущих поосвободит этот ресурс. Потом из ждущих по
какому-либо алгоритму выбирается только кто-какому-либо алгоритму выбирается только кто-
то один, кто следующим захватит ресурс.то один, кто следующим захватит ресурс.
Таким образом, может найтись один такойТаким образом, может найтись один такой
поток, который никогда не получит доступ кпоток, который никогда не получит доступ к
ресурсу, потому что другие потоки постоянноресурсу, потому что другие потоки постоянно
захватывают ресурс раньше него.захватывают ресурс раньше него.
20. livelocklivelock
livelock частая проблема в асинхронныхlivelock частая проблема в асинхронных
системах. Там потоки почти не блокируются насистемах. Там потоки почти не блокируются на
критических ресурсах. Вместо этого оникритических ресурсах. Вместо этого они
выполняют свою небольшую неблокируемуювыполняют свою небольшую неблокируемую
задачу и отправляют её в очередь назадачу и отправляют её в очередь на
обработку другими потоками. Можетобработку другими потоками. Может
возникнуть ситуация, когда потоки друг другувозникнуть ситуация, когда потоки друг другу
начинают перекидывать какое-то событие и егоначинают перекидывать какое-то событие и его
обработка зацикливается. Явного бесконечногообработка зацикливается. Явного бесконечного
цикла, как бы, не происходит, но нагрузка нацикла, как бы, не происходит, но нагрузка на
асинхронную систему резко возрастает. Васинхронную систему резко возрастает. В
результате чего эти потоки больше ничем нерезультате чего эти потоки больше ничем не
успевают занимаются.успевают занимаются.
21.
22.
23. ModificatorModificator volatilevolatile
определение переменной с ключевымопределение переменной с ключевым
словом volatile(«изменчивый») означает,словом volatile(«изменчивый») означает,
что значение переменной будетчто значение переменной будет
изменяться разными потоками.изменяться разными потоками.
чтение volatile переменныхчтение volatile переменных
синхронизировано и запись в volatileсинхронизировано и запись в volatile
переменные синхронизирована, апеременные синхронизирована, а
неатомарные операции – нет.неатомарные операции – нет.
Что означает, что следующий код неЧто означает, что следующий код не
безопасен для потоков:безопасен для потоков:
myVolatileVar++;myVolatileVar++;
26. В чем разница между volatile иВ чем разница между volatile и
synchronized?synchronized?
synchronized имеет два важных момента: это гарантияsynchronized имеет два важных момента: это гарантия
того, что только один поток выполняет секцию кода втого, что только один поток выполняет секцию кода в
один момент времени (взаимоисключение или mutex), иодин момент времени (взаимоисключение или mutex), и
также гарантия того, что данные, изменённые однимтакже гарантия того, что данные, изменённые одним
потоком, будут видны всем другим потокам (видимостьпотоком, будут видны всем другим потокам (видимость
изменений).изменений).
volatile проще, нежели синхронизация и подходит толькоvolatile проще, нежели синхронизация и подходит только
для контроля доступа к одиночному экземпляру илидля контроля доступа к одиночному экземпляру или
переменной примитивного типа: int, boolean... Когдапеременной примитивного типа: int, boolean... Когда
переменная объявлена как volatile, любая запись еёпеременная объявлена как volatile, любая запись её
будет осуществляться прямо в память, минуя кеш. Такжебудет осуществляться прямо в память, минуя кеш. Также
как и считываться будет прямо из памяти, а не изкак и считываться будет прямо из памяти, а не из
всевозможного кеша. Это значит, что все потоки будутвсевозможного кеша. Это значит, что все потоки будут
"видеть" одно и то же значение переменной"видеть" одно и то же значение переменной
одновременно.одновременно.