Задачи и средства многопоточного программирования Java Advanced
2Georgiy Korneev Краткое содержание 1.Классические задачи многопоточного программирования 2.Атомарные операции 3.Блокировки и условия 4.Примитивы синхронизации 5.Решения задач многопоточного программирования 6.Заключение Java Advanced / Задачи и средства многопоточного программирования
Классические задачи многопоточного программирования Часть 1
4Georgiy Korneev Задача доступа к общему ресурсу Несколько потоков обращаются к общему ресурсу Java Advanced / Задачи и средства многопоточного программирования
5Georgiy Korneev Производитель-потребитель Один поток производит данные, второй их потребляет Несколько потоков производят данные и несколько их потребляют Данные могут храниться в очереди (не)ограниченного объема Java Advanced / Задачи и средства многопоточного программирования
6Georgiy Korneev Задача о читателях и писателях Читать могут много потоков одновременно Писать может только один поток Читать во время записи нельзя Java Advanced / Задачи и средства многопоточного программирования
7Georgiy Korneev Задача об обедающих философах 5 Философов, 5 тарелок, 5 вилок Философ Думает Ест Что бы есть нужны обе вилки Java Advanced / Задачи и средства многопоточного программирования
8Georgiy Korneev Задания-работники Поток-клиент ждет выполнения задания потоком-сервером Java Advanced / Задачи и средства многопоточного программирования
Атомарные операции Часть 2
10Georgiy Korneev Атомарная операция Операция выполняемая как единое целое Чтение Запись Неатомарные операции Инкремент Декремент Java Advanced / Задачи и средства многопоточного программирования
11Georgiy Korneev Виды атомарных операций Чтение get Запись set Чтение и запись getAndSet Условная запись compareAndSet Java Advanced / Задачи и средства многопоточного программирования
12Georgiy Korneev Условная запись compareAndSet(old, new) Если текущее значение равно old Установить значение в new Идиома do { old = v.get(); new = process(old); } while (v.compareAndSet(old, new)); Java Advanced / Задачи и средства многопоточного программирования
13Georgiy Korneev Решение задачи доступа к ресурсу // Получение доступа к ресурсу while(!v.compareAndSet(0, 1)); // Действия с ресурсом // Освобождение ресурса v.set(0); Java Advanced / Задачи и средства многопоточного программирования
14Georgiy KorneevJava Advanced / Задачи и средства многопоточного программирования Атомарные операции в Java Чтение / запись get() – атомарное чтение set(value) – атомарная запись lazySet(value) – запись без барьера getAndSet(value) – чтение и запись Проверки compareAndSet(expected, value) – сравнение и запись weakCompareAndSet(expected, value) – слабое сравнение и запись
15Georgiy Korneev Операции над числами Пре- операции getAndIncrement() – инкремент getAndDecrement() – декремент addAndGet() – сложение Пост- операции incrementAndGet() – инкремент decrementAndGet() – декремент getAndAdd() – сложение Java Advanced / Задачи и средства многопоточного программирования
16Georgiy KorneevJava Advanced / Задачи и средства многопоточного программирования Атомарные переменные Типы AtomicBoolean AtomicInteger AtomicLong AtomicReference Операции Обычные
17Georgiy KorneevJava Advanced / Задачи и средства многопоточного программирования Атомарные массивы Типы AtomicIntegerArray AtomicLongArray AtomicReferenceArray Операции Обычные, с указанием индекса length() – число элементов
18Georgiy KorneevJava Advanced / Задачи и средства многопоточного программирования Атомарный доступ к полям Типы AtomicIntegerFieldUpdater AtomicLongFieldUpdater AtomicReferenceFieldUpdater Типы полей volatile не static Операции Обычные, с указанием объекта Создание newUpdater(class, fieldName)
19Georgiy KorneevJava Advanced / Задачи и средства многопоточного программирования Помеченные ссылки Типы AtomicMarkableReference – ссылка помеченная флажком AtomicStampedReference – ссылка помеченная числом
20Georgiy KorneevJava Advanced / Задачи и средства многопоточного программирования Операции с помеченными ссылками Чтения getReference() – прочитать ссылку isMarked() / getStamp() – прочитать пометку V get(X[] holder) – прочитать ссылку и пометку Установки set(valueV, valueX) – установить пометку и значение. attemptX(oldV, newX) – изменить пометку Условной установки compareAndSet(oldV, newV, oldX, newX)
Блокировки и условия Часть 3
22Georgiy Korneev Блокировка Только один поток может владеть блокировкой Операции lockполучить блокировку unlockотдать блокировку tryLockпопробовать получить блокировку Java Advanced / Задачи и средства многопоточного программирования
23Georgiy KorneevJava Advanced / Задачи и средства многопоточного программирования Блокировки в Java Интерфейс Lock Методы lock() – захватить блокировку lockInterruptibly() – захватить блокировку tryLock(time?) – попытаться захватить блокировку unlock() – отпустить блокировку Передача событий newCondition() – создать условие
24Georgiy KorneevJava Advanced / Задачи и средства многопоточного программирования Условия Интерфейс Condition await(time?) – ждать условия awaitUntil(deadline) – ждать условия до времени awaitUninterruptibly() – ждать условие signal() – подать сигнал signalAll() – подать сигнал всем Нужно владеть родительской блокировкой
25Georgiy Korneev Производитель Решение с помощью событий void set(Object data) throws InterruptedException { lock.lock(); try { while (data != null) notFull.await(); this.data = data; notEmpty.signal(); } finally { lock.unlock(); } Java Advanced / Задачи и средства многопоточного программирования
26Georgiy Korneev Особенности Отсутствие «блочности» Разделенные блокировки Необходимость явного отпускания Идиома l.lock() try { … } finally { l.unlock() } Java Advanced / Задачи и средства многопоточного программирования
27Georgiy Korneev Производитель-потребитель Решение с помощью разделенных блокировок Производитель empty.lock(); // копирование full.unlock(); Потребитель full.lock(); // копирование empty.unlock(); Java Advanced / Задачи и средства многопоточного программирования
28Georgiy KorneevJava Advanced / Задачи и средства многопоточного программирования Реализация блокировки Класс ReentrantLock Дополнительные методы isFair() – «честность» блокировки isLocked() – блокировка занята Статистика getQueuedThreads() / getQueueLength() / hasQueuedThread(thread) / hasQueuedThreads() – потоки, ждущие блокировку getWaitingThreads(condition) / getWaitQueueLength(condition) – потоки, ждущие условие
29Georgiy KorneevJava Advanced / Задачи и средства многопоточного программирования Читатели и писатели Интерфейс ReadWriteLock Методы readLock() – блокировка для читателей writeLock() – блокировка для писателей Реализация ReentrantReadWriteLock
Примитивы синхронизации Часть 4
31Georgiy Korneev Критическая секция Только один поток может выполнять действия в критической секции Именованные критические секции Java Advanced / Задачи и средства многопоточного программирования
32Georgiy Korneev Решение задачи доступа к ресурсу Доступ производится в критической секции resource < resource: // Доступ к ресурсу > Java Advanced / Задачи и средства многопоточного программирования
33Georgiy Korneev Реализации критических секций На основе неделимых операций await(!lock) lock = true; // Вход // Критическая секция lock = false;// Выход На основе атомарных операций while(!lock.compareAndSet(0, 1));// Вход // Критическая секция lock.set(0);// Выход Java Advanced / Задачи и средства многопоточного программирования
34Georgiy KorneevJava Advanced / Задачи и средства многопоточного программирования Примитивы синхронизации Semaphore – семафор CyclicBarrier – многоразовый барьер CountDownLatch – защелка Exchanger – рандеву
35Georgiy Korneev Семафор Хранит количество разрешений на вход Операции acquireполучить разрешение releaseдобавить разрешение Доступ к ограниченными ресурсами Java Advanced / Задачи и средства многопоточного программирования
36Georgiy Korneev Реализация семафора С применением атомарных операций Получение разрешения do { p = permits.get(); } while (p == 0); } while (permits.compareAndSet(p, p - 1); Добавление разрешения do { p = permits.get(); } while (permits.compareAndSet(p, p + 1); Java Advanced / Задачи и средства многопоточного программирования
37Georgiy KorneevJava Advanced / Задачи и средства многопоточного программирования Семафоры в Java Конструкторы Semaphore(n, fair?) – число разрешений и честность Методы acquire(n?) – получить разрешение release(n?) – отдать разрешение tryAquire(n?, time?) – попробовать получить разрешение reducePermits(n) – уменьшить количество разрешений drainPermits() – забрать все разрешения статистика
38Georgiy Korneev Барьер Потоки блокируются пока все потоки не прибудут к барьеру Одноразовый Многоразовый Операции arriveприбытие к барьеру Синхронизация потоков Переход к следующему этапу Java Advanced / Задачи и средства многопоточного программирования
39Georgiy KorneevJava Advanced / Задачи и средства многопоточного программирования Барьеры в Java Конструкторы CyclicBarrier(n, runnable?) – число потоков и действие на барьере Методы await(time?) – барьер. reset() – возвращает барьер в исходное состояние isBroken() – «сломан» ли барьер статистикатr
40Georgiy Korneev Монитор Разделяемые переменные инкапсулированы в мониторе Код в мониторе исполняется не более чем одним потоком Условия Операции с условиями waitожидание условия notifyсообщение об условии одному потоку notifyAllсообщение об условии всем потокам Java Advanced / Задачи и средства многопоточного программирования
41Georgiy Korneev Защелки Ожидание завершения нескольких работ Операции countDown() – опускает защелку на единицу await() – ждет спуска защелки Java Advanced / Задачи и средства многопоточного программирования
42Georgiy KorneevJava Advanced / Задачи и средства многопоточного программирования Защелки в Java Конструктор CountDownLatch(n) – высотазащелки Методы await(time?) – ждет спуска защелки countDown() – опускает защелку на единицу getCount() – текущая высота защелки Применение Инициализация
43Georgiy KorneevJava Advanced / Задачи и средства многопоточного программирования Рандеву Позволяет потокам синхронно обмениваться объектами Конструкторы Exchanger() Методы exchange(V x, time?) – обменяться
44Georgiy Korneev Монитор Инкапсулированные переменные Методы Условия Операции с условиями waitожидание условия notifyсообщение об условии одному потоку notifyAllсообщение об условии всем потокам Java Advanced / Задачи и средства многопоточного программирования
Решение классических задач параллельного программирования Часть 4
46Georgiy Korneev Задания-работники Решение с помощью монитора Задание queue.add(task); queue.notify(); task.wait(); Работник while (queue.isEmpty()) queue.wait(); Task t = queue.get(); // Обработка задания t.notify(); Java Advanced / Задачи и средства многопоточного программирования
47Georgiy Korneev Задача об обедающих философах Решение с помощью асимметрии Все философы кроме одного берут сначала левую, затем правую вилку Оставшийся философ берет сначала правую, затем левую вилку Java Advanced / Задачи и средства многопоточного программирования
48Georgiy Korneev Задача о читателях и писателях (1) Решение с помощью блокировки Читатель if (nr++ == 0) busy.lock(); // Чтение if (--nr == 0) busy.unlock(); Писатель busy.lock(); // Запись busy.unlock(); Java Advanced / Задачи и средства многопоточного программирования
49Georgiy Korneev Задача о читателях и писателях (2) Решение с помощью передачи эстафеты Особенности решения Если есть и писатели и читатели, то вход закрывается Пока есть читатели – разрешать чтение Когда нет читателей – разрешить запись Когда нет ни читателей ни писателей – открыть вход Java Advanced / Задачи и средства многопоточного программирования
50Georgiy Korneev Задача о читателях и писателях (3) Java Advanced / Задачи и средства многопоточного программирования
51Georgiy Korneev Задача о читателях и писателях Передача эстафеты if (nw == 0 && dr > 0) { dr--; r.unlock(); // Возобновить процесс-читатель } else if (nr == 0 && nw == 0 && dw > 0) { dw--; w.unlock(); // Возобновить процесс-писатель } else { e.unlock(); // Открыть вход } Java Advanced / Задачи и средства многопоточного программирования
52Georgiy Korneev Задача о читателях и писателях Читатель e.lock(); if (nw > 0) { dr++; e.unlock(); r.lock(); } // Доступ разрешен nr++; // Передача эстафеты // Чтение e.lock(); nr--; // Передача эстафеты Java Advanced / Задачи и средства многопоточного программирования
53Georgiy Korneev Задача о читателях и писателях Писатель e.lock(); if (nw > 0 || nr > 0) { dw++; e.unlock(); w.lock(); } nw++; // Передача эстафеты // Запись e.lock(); nw--; // Передача эстафеты Java Advanced / Задачи и средства многопоточного программирования
Заключение Часть 8
55Georgiy KorneevJava Advanced / Задачи и средства многопоточного программирования Ссылки JSR 166: Concurrency Utilities // Concurrent Programming with J2SE 5.0 // s/J2SE/concurrency/ s/J2SE/concurrency/ Getting to know synchronizers 005/tt0216.html# /tt0216.html#1
56Georgiy Korneev Вопросы Java Advanced / Задачи и средства многопоточного программирования