SlideShare une entreprise Scribd logo
1  sur  35
Язык программирования
JAVA
Лекция# 5
Синхронизация потоков в Java
Моисеенко Антон
canggu@mail.ru
СПГУАП
Кафедра Информационно-Сетевых Технологий
Содержание курса
1. Соревнование потоков
2. Работа с раздельными рессурсами
3. Объект синхронизации
4. Возможные причины блокировки потока
5. Реакция на прерывание потока
6. Межпотоковое взаимодействие
7. Методы wait() и notify()
8. Синхронииизация на примере модели читатель-писатель
9. Deadlock
10. Потоки демоны
11. Исполнение задач по расписанию
Соревнование потоков
■ Соревнование имеет место при участии
нескольких асинхронных потоков,
использующих один и тот же ресурс
(разделяемый ресурс).
■ В данном случае потоки могут возвращать неверные
результаты.
■ Пример:
○ Одновременное чтение и запись в файл может
повредить данные в нем.
■ Проблем можно избежать, если синхронизовать
потоки, использующие разделяемые ресурсы.
■ Так же называется thread race, thread condition.
Работа с разделяемым ресурсом
Класс содержит в себе целое число и методы для
увеличения этого числа на 1 и уменьшения на 1.
public class SeniorStable {
private int horseCount = 10;
public void
returnHorse(){horseCount++;}
public void takeHorse(){horseCount--;}
public int getHorseCount(){
return horseCount;
}
}
Работа с разделяемым ресурсом
final SeniorStable ss = new SeniorStable();
new Thread(“Quest"){ //чтобы выполнить задание
public void run(){ //абсолютно необходима лошадь
while (true){
if(ss.getHorseCount()>0){
ss.takeHorse(); //берем ее в конюшне
doQuest();
ss.returnHorse(); //возвращаем обратно
}
}
}
}.start();
Что будет если два человека
заберут по одной лошади?
Если запустить несколько потоков, то может случиться так, что два человека
одновременно забирают последнюю лошадь.
В конюшне остается -1 лошадь?!
Решение: попытка №1
public class SeniorStable {
private int horseCount = 10;
public void returnHorse(){horseCount++;}
public void takeHorse(){
(if horseCount>0) horseCount--;
}
public int getHorseCount(){
return horseCount;
}
}
■Задания выполнены, лошадей вернули.
■В конюшне появилась лишняя лошадь!
■Волшебство продолжается?
Решение: попытка №2
Метод или блок кода, выполнение которого не должно
прерываться исполнением того же самого кода но на другом
потоке, можно помечать модификатором synchronized.
public class SeniorStable {
private int horseCount = 10;
public void synchronized returnHorse(){
horseCount++;}
public void synchronized takeHorse(){ horseCount--
;}
public int synchronized getHorseCount(){
return horseCount;
}
}
Объект синхронизации
▪Для задания синхронизации между методами
нужен некий объект.
▪Обычно таким объектом является разделяемый
ресурс.
▪Синхронизованный метод становится
«владельцем» монитора объекта.
▪Разделяемым ресурсом может быть
o ссылочный тип (объект)
▪класс
Объект синхронизации
В данном случае объектом синхронизации потоков
является horseCount – ссылочный тип.
public class SeniorStable {
private Integer horseCount = new Integer(10);
public void returnHorse(){horseCount++;}
public void takeHorse(){
synchronized(horseCount) {horseCount--;}
}
public int getHorseCount(){
return horseCount;
}
}
Объект синхронизации: класс
При этом синхронизация происходит по объекту класса
SeniorStable
public class SeniorStable {
private int horseCount = 10;
public void synchronized returnHorse(){
horseCount++;
}
public void synchronized takeHorse(){
horseCount--;
}
public int synchronized getHorseCount(){
return horseCount;
}
}
Возможные причины
блокировки потока
▪ Был вызван метод sleep().
o Поток блокируется на определенное время.
o По истечению этого времени поток
переводится в активное состояние.
▪ Поток пытается войти в критический участок,
но соответствующий ресурс заблокирован
каким-то другим потоком.
o Данный поток блокируется до тех пор, пока
не будет разблокирован этот ресурс (если
нет других потоков, ожидающих тот же
ресурс).
Возможные причины
блокировки потока
▪ Поток выполняет операцию ввода/вывода.
o Поток блокируется до окончания этой
операции.
▪ У потока был вызван метод wait().
o Поток блокируется до окончания отведенного
временного интервала или вызова метода
notify() или notifyAll().
Реакция на прерывание потока
Во время ожидания может произойти прерывание.
Их необходимо обработать:
public class Quest extends Thread{
public void run(){
try {
sleep(100);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
Межпотоковое взаимодействие
Следующие методы класса Object используются для
реализации взаимодействия потоков между собой.
public final void
wait() throws
InterruptedException
Заставляет поток ожидать когда какой-
то другой поток вызовет метод notify()
или notifyAll() для данного объекта.
public final void
notify()
Пробуждает поток, который вызвал
метод wait() для этого же объекта.
public final void
notifyAll()
Пробуждает все потоки, который
вызвали метод wait() для этого же
объекта.
Метод Object.wait() (cont.)
▪ При вызове метода wait() поток становится
недоступным для диспетчеризации (ему не может
быть передано управление) до тех пор, пока не
выполнится одно из следующих условий:
▪ Другой поток вызвал метод notify().
▪ Другой поток вызвал метод notifyAll().
▪ Другой поток прервал ожидающий поток.
▪ Заданный интервал времени истек (wait(long millis))
▪ После выполнения одного из условий поток
становится снова диспетчеризуемым.
Метод Object.notify()
▪ Пробуждает один поток, ожидающий на данном
объекте.
▪ Если ожидают много потоков, то для пробуждения выбирается только
один из них.
▪ Выбор зависит от реализации.
▪ Может вызываться только внутри синхронизованных
секций.
▪ Пробужденный поток не способен продолжать
работать до тех пор, пока текущий поток не
освободит объект (не покинет синхронизованный
блок).
Читатель-писатель
▪ Два потока взаимодействуют между собой
посредством некоторого хранилища данных.
▪ Первый поток (писатель) в хранилище записывает
данные.
▪ Второй поток (читатель) из хранилища считывает
данные, затем удаляя их.
▪ Решение данной задачи предполагает наличие
некого протокола взаимодействия двух потоков.
Несинхронизованное взаимодействие
Класс-абстракция разделяемого ресурса.
public class CubbyHole {
private int contents;
public int get() {
return contents;
}
public synchronized void put(int value){
contents = value;
}
}
Класс Писатель
Писатель помещает число и ждет случайный по
длительности
public class Producer extends Thread {
private CubbyHole cubbyhole;
private int number;
public Producer(CubbyHole c, int number) {
cubbyhole = c;
this.number = number;
}
Класс Писатель
public void run() {
for (int i = 0; i < 10; i++) {
cubbyhole.put(i);
System.out.println("Producer #" +
this.number
+ " put: " + i);
try {
sleep((int)(Math.random() *
100));
} catch (InterruptedException e) { }
}
}
}
ости интервал времени.
Класс Читатель
Читатель считывает число.
public class Consumer extends Thread {
private CubbyHole cubbyhole;
private int number;
public Consumer(CubbyHole c, int number) {
cubbyhole = c;
this.number = number;
}
public void run() {
int value = 0;
for (int i = 0; i < 10; i++) {
value = cubbyhole.get();
System.out.println("Consumer #" +
this.number
+ " got: " + value);
}
}
}
Запуск программы
Класс, создающий независимые потоки Писателя и Читателя.
public class ProducerConsumerUnsynchronized {
public static void main(String[] args) {
CubbyHole c = new CubbyHole();
Producer p1 = new Producer(c, 1);
Consumer c1 = new Consumer(c, 1);
p1.start();
c1.start();
}
}
Результат работы
■ Непредсказуемые.
○ Одно число может быть прочитано множество раз.
○ Число может не быть прочитано ни разу.
Consumer #1 got: 0
Producer #1 put: 0
Consumer #1 got: 0
Consumer #1 got: 0
Consumer #1 got: 0
Consumer #1 got: 0
Consumer #1 got: 0
Consumer #1 got: 0
Consumer #1 got: 0
Consumer #1 got: 0
Consumer #1 got: 0
Результат работы
Producer #1 put: 1
Producer #1 put: 2
Producer #1 put: 3
Producer #1 put: 4
Producer #1 put: 5
Producer #1 put: 6
Producer #1 put: 7
Producer #1 put: 8
Producer #1 put: 9
Правильное решение
Синхронизация доступа к разделяемому ресурсу.
public class CubbyHole {
private int contents;
private boolean available = false;
public synchronized int get() {
while (available == false) {
try {
wait();
} catch (InterruptedException e) { }
}
available = false;
notifyAll();
return contents;
}
// continued
Правильное решение
Синхронизация доступа к разделяемому ресурсу.
public synchronized void put(int value) {
while (available == true) {
try {
wait();
} catch (InterruptedException e) { }
}
contents = value;
available = true;
notifyAll();
}
Результат работы
■ Предсказуемые.
○ Каждому записанному числу соответствует единственное
чтение.
Producer 1 put: 0
Consumer 1 got: 0
Producer 1 put: 1
Consumer 1 got: 1
Producer 1 put: 2
Consumer 1 got: 2
Producer 1 put: 3
Consumer 1 got: 3
Producer 1 put: 4
Consumer 1 got: 4
Producer 1 put: 5
Consumer 1 got: 5
Producer 1 put: 6
Consumer 1 got: 6
Producer 1 put: 7
Consumer 1 got: 7
Producer 1 put: 8
Consumer 1 got: 8
Producer 1 put: 9
Consumer 1 got: 9
Повторное использование
блокировок
Вызов синхронизованного метода из другого
синхронизованного метода возможен при условии что объект
синхронизации одинаков.
public synchronized void first(){
second();
}
public synchronized void second(){..}
Тупик (deadlock)
• Тупиком называется состояние взаимной блокировки потоков,
каждому из которых требуется ресурс, блокируемый другим
потоком.
• Так же называется взаимная блокировка или клинч.
synchronized(a){
synchronized(b) {…}
}
…
synchronized(b){
synchronized(a) {…}
}
Демон (daemon)
• Поток с выставленным флагом isDaemon называется
демоном.
• Потоки-демоны, в отличие от обычных потоков, не
препятствуют завершению работы виртуальной машины.
• Если поток-демон создает другие потоки, то они также
получат статус потока-демона.
public class ColdWarDaemon extends Thread{
public ColdWarDaemon()
setDaemon(true);
start();
}
public void run(){
while (true){…}
}
Исполнение по расписанию
■ Класс Timer.
• Предоставляет возможность выполнить
задание в будущем (поставить в очередь) в отдельном
потоке.
• Задания могут выполняться единожды или через
указанный интервал времени.
• Каждый класс Timer владеет потоком, на котором
исполняются все задания.
■ Класс TimerTask.
• Абстрактный класс с абстрактным методом run().
• Конкретный класс должен реализовать метод run().
Пример исполнения по
расписанию
Сообщение выдается через несколько секунд после
инициализации приложения.
public class TimerReminder {
Timer timer;
public TimerReminder(int seconds) {
timer = new Timer();
timer.schedule(new RemindTask(),
seconds*1000);
}
Пример исполнения по
расписанию
class RemindTask extends TimerTask {
public void run() {
System.out.format("Time's up!%n");
timer.cancel();//Terminate the timer thread
}
}
public static void main(String args[]) {
System.out.format("About to schedule task.%n");
new TimerReminder(5);
System.out.format("Task scheduled.%n");
}
}
Вопросы?

Contenu connexe

Tendances

C++ STL & Qt. Занятие 05.
C++ STL & Qt. Занятие 05.C++ STL & Qt. Занятие 05.
C++ STL & Qt. Занятие 05.Igor Shkulipa
 
C++ STL & Qt. Занятие 04.
C++ STL & Qt. Занятие 04.C++ STL & Qt. Занятие 04.
C++ STL & Qt. Занятие 04.Igor Shkulipa
 
C++ STL & Qt. Занятие 07.
C++ STL & Qt. Занятие 07.C++ STL & Qt. Занятие 07.
C++ STL & Qt. Занятие 07.Igor Shkulipa
 
C++ STL & Qt. Занятие 03.
C++ STL & Qt. Занятие 03.C++ STL & Qt. Занятие 03.
C++ STL & Qt. Занятие 03.Igor Shkulipa
 
C++ STL & Qt. Занятие 01.
C++ STL & Qt. Занятие 01.C++ STL & Qt. Занятие 01.
C++ STL & Qt. Занятие 01.Igor Shkulipa
 
C++ STL & Qt. Занятие 06.
C++ STL & Qt. Занятие 06.C++ STL & Qt. Занятие 06.
C++ STL & Qt. Занятие 06.Igor Shkulipa
 
C++ STL & Qt. Занятие 02.
C++ STL & Qt. Занятие 02.C++ STL & Qt. Занятие 02.
C++ STL & Qt. Занятие 02.Igor Shkulipa
 
Java. Многопоточность.
Java. Многопоточность.Java. Многопоточность.
Java. Многопоточность.Unguryan Vitaliy
 
C++ STL & Qt. Занятие 09.
C++ STL & Qt. Занятие 09.C++ STL & Qt. Занятие 09.
C++ STL & Qt. Занятие 09.Igor Shkulipa
 
C++ весна 2014 лекция 5
C++ весна 2014 лекция 5C++ весна 2014 лекция 5
C++ весна 2014 лекция 5Technopark
 
Java. Сборщик мусора. Работа с памятью.
Java.  Сборщик мусора. Работа с памятью. Java.  Сборщик мусора. Работа с памятью.
Java. Сборщик мусора. Работа с памятью. Unguryan Vitaliy
 
Java осень 2014 занятие 3
Java осень 2014 занятие 3Java осень 2014 занятие 3
Java осень 2014 занятие 3Technopark
 
Java core-lect6-part3-annotation.ppt
Java core-lect6-part3-annotation.pptJava core-lect6-part3-annotation.ppt
Java core-lect6-part3-annotation.pptAnton Moiseenko
 
Java осень 2014 занятие 5
Java осень 2014 занятие 5Java осень 2014 занятие 5
Java осень 2014 занятие 5Technopark
 
Системы контроля версий
Системы контроля версийСистемы контроля версий
Системы контроля версийUnguryan Vitaliy
 

Tendances (16)

C++ STL & Qt. Занятие 05.
C++ STL & Qt. Занятие 05.C++ STL & Qt. Занятие 05.
C++ STL & Qt. Занятие 05.
 
C++ STL & Qt. Занятие 04.
C++ STL & Qt. Занятие 04.C++ STL & Qt. Занятие 04.
C++ STL & Qt. Занятие 04.
 
C++ STL & Qt. Занятие 07.
C++ STL & Qt. Занятие 07.C++ STL & Qt. Занятие 07.
C++ STL & Qt. Занятие 07.
 
C++ STL & Qt. Занятие 03.
C++ STL & Qt. Занятие 03.C++ STL & Qt. Занятие 03.
C++ STL & Qt. Занятие 03.
 
C++ STL & Qt. Занятие 01.
C++ STL & Qt. Занятие 01.C++ STL & Qt. Занятие 01.
C++ STL & Qt. Занятие 01.
 
C++ STL & Qt. Занятие 06.
C++ STL & Qt. Занятие 06.C++ STL & Qt. Занятие 06.
C++ STL & Qt. Занятие 06.
 
C++ STL & Qt. Занятие 02.
C++ STL & Qt. Занятие 02.C++ STL & Qt. Занятие 02.
C++ STL & Qt. Занятие 02.
 
Java. Многопоточность.
Java. Многопоточность.Java. Многопоточность.
Java. Многопоточность.
 
C++ STL & Qt. Занятие 09.
C++ STL & Qt. Занятие 09.C++ STL & Qt. Занятие 09.
C++ STL & Qt. Занятие 09.
 
C++ весна 2014 лекция 5
C++ весна 2014 лекция 5C++ весна 2014 лекция 5
C++ весна 2014 лекция 5
 
Java. Сборщик мусора. Работа с памятью.
Java.  Сборщик мусора. Работа с памятью. Java.  Сборщик мусора. Работа с памятью.
Java. Сборщик мусора. Работа с памятью.
 
Java осень 2014 занятие 3
Java осень 2014 занятие 3Java осень 2014 занятие 3
Java осень 2014 занятие 3
 
java
javajava
java
 
Java core-lect6-part3-annotation.ppt
Java core-lect6-part3-annotation.pptJava core-lect6-part3-annotation.ppt
Java core-lect6-part3-annotation.ppt
 
Java осень 2014 занятие 5
Java осень 2014 занятие 5Java осень 2014 занятие 5
Java осень 2014 занятие 5
 
Системы контроля версий
Системы контроля версийСистемы контроля версий
Системы контроля версий
 

Similaire à Java Core. Lecture# 5. Concurrency.

Programming Java - Lection 06 - Multithreading - Lavrentyev Fedor
Programming Java - Lection 06 - Multithreading - Lavrentyev FedorProgramming Java - Lection 06 - Multithreading - Lavrentyev Fedor
Programming Java - Lection 06 - Multithreading - Lavrentyev FedorFedor Lavrentyev
 
Java весна 2014 лекция 5
Java весна 2014 лекция 5Java весна 2014 лекция 5
Java весна 2014 лекция 5Technopark
 
Многопоточность, работа с сетью (Lecture 12 – multithreading, network)
Многопоточность, работа с сетью (Lecture 12 – multithreading, network)Многопоточность, работа с сетью (Lecture 12 – multithreading, network)
Многопоточность, работа с сетью (Lecture 12 – multithreading, network)Noveo
 
PostSharp - Threading Model Library
PostSharp - Threading Model LibraryPostSharp - Threading Model Library
PostSharp - Threading Model LibraryAndrey Gordienkov
 
Expert Java Day: Java concurrency
Expert Java Day: Java concurrencyExpert Java Day: Java concurrency
Expert Java Day: Java concurrencyPavel Titkov
 
Лекция 6
Лекция 6Лекция 6
Лекция 6itc73
 
Семь тысяч Rps, один go
Семь тысяч Rps, один goСемь тысяч Rps, один go
Семь тысяч Rps, один goBadoo Development
 
MongoDB в продакшен - миф или реальность?
MongoDB в продакшен - миф или реальность?MongoDB в продакшен - миф или реальность?
MongoDB в продакшен - миф или реальность?Alexey Tokar
 
Java осень 2013 лекция 6
Java осень 2013 лекция 6Java осень 2013 лекция 6
Java осень 2013 лекция 6Technopark
 
8. java lecture threads
8. java lecture threads8. java lecture threads
8. java lecture threadsMERA_school
 
Dependency injection
Dependency injectionDependency injection
Dependency injectionGetDev.NET
 
Svitla .Net meetup in Kiev, Anzhiiak Oleksii
Svitla .Net meetup in Kiev, Anzhiiak OleksiiSvitla .Net meetup in Kiev, Anzhiiak Oleksii
Svitla .Net meetup in Kiev, Anzhiiak OleksiiSvitla Systems Inc.
 
Multithreading in java past and actual
Multithreading in java past and actualMultithreading in java past and actual
Multithreading in java past and actualYevgen Levik
 
JPoint 2016 - Etudes of DIY Java profiler
JPoint 2016 - Etudes of DIY Java profilerJPoint 2016 - Etudes of DIY Java profiler
JPoint 2016 - Etudes of DIY Java profilerAnton Arhipov
 
Этюды о буферизации: асинхронные оповещения, репликация обновлений, объединен...
Этюды о буферизации: асинхронные оповещения, репликация обновлений, объединен...Этюды о буферизации: асинхронные оповещения, репликация обновлений, объединен...
Этюды о буферизации: асинхронные оповещения, репликация обновлений, объединен...corehard_by
 
Java tricks for high-load server programming
Java tricks for high-load server programmingJava tricks for high-load server programming
Java tricks for high-load server programmingAndrei Pangin
 
Java осень 2014 занятие 6
Java осень 2014 занятие 6Java осень 2014 занятие 6
Java осень 2014 занятие 6Technopark
 
Async Javascript
Async JavascriptAsync Javascript
Async JavascriptGetDev.NET
 

Similaire à Java Core. Lecture# 5. Concurrency. (20)

Programming Java - Lection 06 - Multithreading - Lavrentyev Fedor
Programming Java - Lection 06 - Multithreading - Lavrentyev FedorProgramming Java - Lection 06 - Multithreading - Lavrentyev Fedor
Programming Java - Lection 06 - Multithreading - Lavrentyev Fedor
 
Java весна 2014 лекция 5
Java весна 2014 лекция 5Java весна 2014 лекция 5
Java весна 2014 лекция 5
 
Многопоточность, работа с сетью (Lecture 12 – multithreading, network)
Многопоточность, работа с сетью (Lecture 12 – multithreading, network)Многопоточность, работа с сетью (Lecture 12 – multithreading, network)
Многопоточность, работа с сетью (Lecture 12 – multithreading, network)
 
PostSharp - Threading Model
PostSharp - Threading ModelPostSharp - Threading Model
PostSharp - Threading Model
 
PostSharp - Threading Model Library
PostSharp - Threading Model LibraryPostSharp - Threading Model Library
PostSharp - Threading Model Library
 
Expert Java Day: Java concurrency
Expert Java Day: Java concurrencyExpert Java Day: Java concurrency
Expert Java Day: Java concurrency
 
Лекция 6
Лекция 6Лекция 6
Лекция 6
 
Семь тысяч Rps, один go
Семь тысяч Rps, один goСемь тысяч Rps, один go
Семь тысяч Rps, один go
 
MongoDB в продакшен - миф или реальность?
MongoDB в продакшен - миф или реальность?MongoDB в продакшен - миф или реальность?
MongoDB в продакшен - миф или реальность?
 
Javascript 1
Javascript 1Javascript 1
Javascript 1
 
Java осень 2013 лекция 6
Java осень 2013 лекция 6Java осень 2013 лекция 6
Java осень 2013 лекция 6
 
8. java lecture threads
8. java lecture threads8. java lecture threads
8. java lecture threads
 
Dependency injection
Dependency injectionDependency injection
Dependency injection
 
Svitla .Net meetup in Kiev, Anzhiiak Oleksii
Svitla .Net meetup in Kiev, Anzhiiak OleksiiSvitla .Net meetup in Kiev, Anzhiiak Oleksii
Svitla .Net meetup in Kiev, Anzhiiak Oleksii
 
Multithreading in java past and actual
Multithreading in java past and actualMultithreading in java past and actual
Multithreading in java past and actual
 
JPoint 2016 - Etudes of DIY Java profiler
JPoint 2016 - Etudes of DIY Java profilerJPoint 2016 - Etudes of DIY Java profiler
JPoint 2016 - Etudes of DIY Java profiler
 
Этюды о буферизации: асинхронные оповещения, репликация обновлений, объединен...
Этюды о буферизации: асинхронные оповещения, репликация обновлений, объединен...Этюды о буферизации: асинхронные оповещения, репликация обновлений, объединен...
Этюды о буферизации: асинхронные оповещения, репликация обновлений, объединен...
 
Java tricks for high-load server programming
Java tricks for high-load server programmingJava tricks for high-load server programming
Java tricks for high-load server programming
 
Java осень 2014 занятие 6
Java осень 2014 занятие 6Java осень 2014 занятие 6
Java осень 2014 занятие 6
 
Async Javascript
Async JavascriptAsync Javascript
Async Javascript
 

Java Core. Lecture# 5. Concurrency.

  • 1. Язык программирования JAVA Лекция# 5 Синхронизация потоков в Java Моисеенко Антон canggu@mail.ru СПГУАП Кафедра Информационно-Сетевых Технологий
  • 2. Содержание курса 1. Соревнование потоков 2. Работа с раздельными рессурсами 3. Объект синхронизации 4. Возможные причины блокировки потока 5. Реакция на прерывание потока 6. Межпотоковое взаимодействие 7. Методы wait() и notify() 8. Синхронииизация на примере модели читатель-писатель 9. Deadlock 10. Потоки демоны 11. Исполнение задач по расписанию
  • 3. Соревнование потоков ■ Соревнование имеет место при участии нескольких асинхронных потоков, использующих один и тот же ресурс (разделяемый ресурс). ■ В данном случае потоки могут возвращать неверные результаты. ■ Пример: ○ Одновременное чтение и запись в файл может повредить данные в нем. ■ Проблем можно избежать, если синхронизовать потоки, использующие разделяемые ресурсы. ■ Так же называется thread race, thread condition.
  • 4. Работа с разделяемым ресурсом Класс содержит в себе целое число и методы для увеличения этого числа на 1 и уменьшения на 1. public class SeniorStable { private int horseCount = 10; public void returnHorse(){horseCount++;} public void takeHorse(){horseCount--;} public int getHorseCount(){ return horseCount; } }
  • 5. Работа с разделяемым ресурсом final SeniorStable ss = new SeniorStable(); new Thread(“Quest"){ //чтобы выполнить задание public void run(){ //абсолютно необходима лошадь while (true){ if(ss.getHorseCount()>0){ ss.takeHorse(); //берем ее в конюшне doQuest(); ss.returnHorse(); //возвращаем обратно } } } }.start();
  • 6. Что будет если два человека заберут по одной лошади? Если запустить несколько потоков, то может случиться так, что два человека одновременно забирают последнюю лошадь. В конюшне остается -1 лошадь?!
  • 7. Решение: попытка №1 public class SeniorStable { private int horseCount = 10; public void returnHorse(){horseCount++;} public void takeHorse(){ (if horseCount>0) horseCount--; } public int getHorseCount(){ return horseCount; } } ■Задания выполнены, лошадей вернули. ■В конюшне появилась лишняя лошадь! ■Волшебство продолжается?
  • 8. Решение: попытка №2 Метод или блок кода, выполнение которого не должно прерываться исполнением того же самого кода но на другом потоке, можно помечать модификатором synchronized. public class SeniorStable { private int horseCount = 10; public void synchronized returnHorse(){ horseCount++;} public void synchronized takeHorse(){ horseCount-- ;} public int synchronized getHorseCount(){ return horseCount; } }
  • 9. Объект синхронизации ▪Для задания синхронизации между методами нужен некий объект. ▪Обычно таким объектом является разделяемый ресурс. ▪Синхронизованный метод становится «владельцем» монитора объекта. ▪Разделяемым ресурсом может быть o ссылочный тип (объект) ▪класс
  • 10. Объект синхронизации В данном случае объектом синхронизации потоков является horseCount – ссылочный тип. public class SeniorStable { private Integer horseCount = new Integer(10); public void returnHorse(){horseCount++;} public void takeHorse(){ synchronized(horseCount) {horseCount--;} } public int getHorseCount(){ return horseCount; } }
  • 11. Объект синхронизации: класс При этом синхронизация происходит по объекту класса SeniorStable public class SeniorStable { private int horseCount = 10; public void synchronized returnHorse(){ horseCount++; } public void synchronized takeHorse(){ horseCount--; } public int synchronized getHorseCount(){ return horseCount; } }
  • 12. Возможные причины блокировки потока ▪ Был вызван метод sleep(). o Поток блокируется на определенное время. o По истечению этого времени поток переводится в активное состояние. ▪ Поток пытается войти в критический участок, но соответствующий ресурс заблокирован каким-то другим потоком. o Данный поток блокируется до тех пор, пока не будет разблокирован этот ресурс (если нет других потоков, ожидающих тот же ресурс).
  • 13. Возможные причины блокировки потока ▪ Поток выполняет операцию ввода/вывода. o Поток блокируется до окончания этой операции. ▪ У потока был вызван метод wait(). o Поток блокируется до окончания отведенного временного интервала или вызова метода notify() или notifyAll().
  • 14. Реакция на прерывание потока Во время ожидания может произойти прерывание. Их необходимо обработать: public class Quest extends Thread{ public void run(){ try { sleep(100); } catch (InterruptedException ex) { ex.printStackTrace(); } }
  • 15. Межпотоковое взаимодействие Следующие методы класса Object используются для реализации взаимодействия потоков между собой. public final void wait() throws InterruptedException Заставляет поток ожидать когда какой- то другой поток вызовет метод notify() или notifyAll() для данного объекта. public final void notify() Пробуждает поток, который вызвал метод wait() для этого же объекта. public final void notifyAll() Пробуждает все потоки, который вызвали метод wait() для этого же объекта.
  • 16. Метод Object.wait() (cont.) ▪ При вызове метода wait() поток становится недоступным для диспетчеризации (ему не может быть передано управление) до тех пор, пока не выполнится одно из следующих условий: ▪ Другой поток вызвал метод notify(). ▪ Другой поток вызвал метод notifyAll(). ▪ Другой поток прервал ожидающий поток. ▪ Заданный интервал времени истек (wait(long millis)) ▪ После выполнения одного из условий поток становится снова диспетчеризуемым.
  • 17. Метод Object.notify() ▪ Пробуждает один поток, ожидающий на данном объекте. ▪ Если ожидают много потоков, то для пробуждения выбирается только один из них. ▪ Выбор зависит от реализации. ▪ Может вызываться только внутри синхронизованных секций. ▪ Пробужденный поток не способен продолжать работать до тех пор, пока текущий поток не освободит объект (не покинет синхронизованный блок).
  • 18. Читатель-писатель ▪ Два потока взаимодействуют между собой посредством некоторого хранилища данных. ▪ Первый поток (писатель) в хранилище записывает данные. ▪ Второй поток (читатель) из хранилища считывает данные, затем удаляя их. ▪ Решение данной задачи предполагает наличие некого протокола взаимодействия двух потоков.
  • 19. Несинхронизованное взаимодействие Класс-абстракция разделяемого ресурса. public class CubbyHole { private int contents; public int get() { return contents; } public synchronized void put(int value){ contents = value; } }
  • 20. Класс Писатель Писатель помещает число и ждет случайный по длительности public class Producer extends Thread { private CubbyHole cubbyhole; private int number; public Producer(CubbyHole c, int number) { cubbyhole = c; this.number = number; }
  • 21. Класс Писатель public void run() { for (int i = 0; i < 10; i++) { cubbyhole.put(i); System.out.println("Producer #" + this.number + " put: " + i); try { sleep((int)(Math.random() * 100)); } catch (InterruptedException e) { } } } } ости интервал времени.
  • 22. Класс Читатель Читатель считывает число. public class Consumer extends Thread { private CubbyHole cubbyhole; private int number; public Consumer(CubbyHole c, int number) { cubbyhole = c; this.number = number; } public void run() { int value = 0; for (int i = 0; i < 10; i++) { value = cubbyhole.get(); System.out.println("Consumer #" + this.number + " got: " + value); } } }
  • 23. Запуск программы Класс, создающий независимые потоки Писателя и Читателя. public class ProducerConsumerUnsynchronized { public static void main(String[] args) { CubbyHole c = new CubbyHole(); Producer p1 = new Producer(c, 1); Consumer c1 = new Consumer(c, 1); p1.start(); c1.start(); } }
  • 24. Результат работы ■ Непредсказуемые. ○ Одно число может быть прочитано множество раз. ○ Число может не быть прочитано ни разу. Consumer #1 got: 0 Producer #1 put: 0 Consumer #1 got: 0 Consumer #1 got: 0 Consumer #1 got: 0 Consumer #1 got: 0 Consumer #1 got: 0 Consumer #1 got: 0 Consumer #1 got: 0 Consumer #1 got: 0 Consumer #1 got: 0
  • 25. Результат работы Producer #1 put: 1 Producer #1 put: 2 Producer #1 put: 3 Producer #1 put: 4 Producer #1 put: 5 Producer #1 put: 6 Producer #1 put: 7 Producer #1 put: 8 Producer #1 put: 9
  • 26. Правильное решение Синхронизация доступа к разделяемому ресурсу. public class CubbyHole { private int contents; private boolean available = false; public synchronized int get() { while (available == false) { try { wait(); } catch (InterruptedException e) { } } available = false; notifyAll(); return contents; } // continued
  • 27. Правильное решение Синхронизация доступа к разделяемому ресурсу. public synchronized void put(int value) { while (available == true) { try { wait(); } catch (InterruptedException e) { } } contents = value; available = true; notifyAll(); }
  • 28. Результат работы ■ Предсказуемые. ○ Каждому записанному числу соответствует единственное чтение. Producer 1 put: 0 Consumer 1 got: 0 Producer 1 put: 1 Consumer 1 got: 1 Producer 1 put: 2 Consumer 1 got: 2 Producer 1 put: 3 Consumer 1 got: 3 Producer 1 put: 4 Consumer 1 got: 4 Producer 1 put: 5 Consumer 1 got: 5 Producer 1 put: 6 Consumer 1 got: 6 Producer 1 put: 7 Consumer 1 got: 7 Producer 1 put: 8 Consumer 1 got: 8 Producer 1 put: 9 Consumer 1 got: 9
  • 29. Повторное использование блокировок Вызов синхронизованного метода из другого синхронизованного метода возможен при условии что объект синхронизации одинаков. public synchronized void first(){ second(); } public synchronized void second(){..}
  • 30. Тупик (deadlock) • Тупиком называется состояние взаимной блокировки потоков, каждому из которых требуется ресурс, блокируемый другим потоком. • Так же называется взаимная блокировка или клинч. synchronized(a){ synchronized(b) {…} } … synchronized(b){ synchronized(a) {…} }
  • 31. Демон (daemon) • Поток с выставленным флагом isDaemon называется демоном. • Потоки-демоны, в отличие от обычных потоков, не препятствуют завершению работы виртуальной машины. • Если поток-демон создает другие потоки, то они также получат статус потока-демона. public class ColdWarDaemon extends Thread{ public ColdWarDaemon() setDaemon(true); start(); } public void run(){ while (true){…} }
  • 32. Исполнение по расписанию ■ Класс Timer. • Предоставляет возможность выполнить задание в будущем (поставить в очередь) в отдельном потоке. • Задания могут выполняться единожды или через указанный интервал времени. • Каждый класс Timer владеет потоком, на котором исполняются все задания. ■ Класс TimerTask. • Абстрактный класс с абстрактным методом run(). • Конкретный класс должен реализовать метод run().
  • 33. Пример исполнения по расписанию Сообщение выдается через несколько секунд после инициализации приложения. public class TimerReminder { Timer timer; public TimerReminder(int seconds) { timer = new Timer(); timer.schedule(new RemindTask(), seconds*1000); }
  • 34. Пример исполнения по расписанию class RemindTask extends TimerTask { public void run() { System.out.format("Time's up!%n"); timer.cancel();//Terminate the timer thread } } public static void main(String args[]) { System.out.format("About to schedule task.%n"); new TimerReminder(5); System.out.format("Task scheduled.%n"); } }