Java Advanced Многопоточное программирование на Java Содержание СПбГУ ИТМО Потоки Блокировки (синхронизация) Мониторы и условия Модель памяти Java Примеры Заключение Georgiy Korneev Java Advanced / Многопоточное программирование. Средства языка Java 2 Часть 1 Потоки Создание потоков Класс Thread – поток Позволяет создавать потоки и производить операции с ними Интерфейс Runnable – сущность, которая может быть запущена public void run(); Georgiy Korneev Java Advanced / Collections Framework 4 Создание потока (Runnable) Пример кода // Создание потока Thread t = new Thread(new Runnable() { public void run() { System.out.println("Hello"); } }); // Запуск потока t.start(); Georgiy Korneev Java Advanced / Collections Framework 5 Создание потока (Thread) Не рекомендуется использовать Пример кода // Создание потока Thread t = new Thread() { public void run() { System.out.println("Hello"); } }; // Запуск потока t.start(); Georgiy Korneev Java Advanced / Collections Framework 6 Состояния потока Состояние потока возвращается методами int getState() и boolean isAlive() класса Thread getState() NEW RUNNABLE BLOCKED WAITING TIMED_WAITING TERMINATED Georgiy Korneev isAlive() + + + + Java Advanced / Collections Framework 7 Свойства потока Основные свойства id – идентификатор потока name – имя потока priority – приоритет daemon – поток-демон Свойства потока не могут изменяться после запуска Georgiy Korneev Java Advanced / Collections Framework 8 Взаимодействие потоков Создание потока Запуск потока Ожидание окончания потока Прерывание потока Georgiy Korneev Java Advanced / Collections Framework 9 Ожидание окончания потока Методы класса Thread join() – ожидать до завершения join(long millis) – ожидать до завершения или истечения millis миллисекунд join(long millis, long nanos) – ожидать до завершения или истечения millis миллисекунд и nanos миллисекунд Все методы ожидания кидают InterruptedExcepton Georgiy Korneev Java Advanced / Collections Framework 10 Прерывание потока Методы класса Thread interrupt() – установить флаг прерывания isInterrupted() – проверить флаг прерывания interrupted() – проверить и сбросить флаг прерывания Методы, которые ожидают в процессе выполнения должны бросать InterruptedException Georgiy Korneev Java Advanced / Collections Framework 11 Дополнительные методы Приостановка выполнения sleep(time) – приостановить поток на время yield() – позволить выполниться другим потокам Получение текущего потока currentThread() Georgiy Korneev Java Advanced / Collections Framework 12 Часть 2 Блокировки (синхронизация) Общий случай Любой объект может служить блокировкой Снятие блокировки производится автоматически Синтаксис synchronized (o) { // Получение блокировки … } // Снятие блокировки Georgiy Korneev Java Advanced / Collections Framework 14 Методы экземпляра Метод экземпляра может быть объявлен синхронизованным public synchronized int getValue() { … } Эквивалентно public int getValue() { synchronized (this) { … } } Georgiy Korneev Java Advanced / Collections Framework 15 Производитель-потребитель (1) Класс данных class Data { private Object data; public void set(Object data) { … } public Object get() { … } } Georgiy Korneev Java Advanced / Collections Framework 16 Производитель-потребитель (2) Установка значения public void set(Object data) { while (true) { synchronized (this) { if (data == null) { this.data = data; break; } } } } Georgiy Korneev Java Advanced / Collections Framework 17 Производитель-потребитель (3) Получение значения public Object get() { while (true) { synchronized (this) { if (data != null) { Object d = data; data = null; return d; } } } } Georgiy Korneev Java Advanced / Collections Framework 18 Часть 3 Мониторы (условия) Монитор Любой объект может быть монитором Для взаимодействия с монитором поток должен иметь блокировку на него Методы монитора wait(time?) – ожидание монитора notify() – извещение одного из ждущих потоков notifyAll() – извещение всех ждущих потоков Georgiy Korneev Java Advanced / Collections Framework 20 Мониторы и блокировки При ожидании монитора блокировка с него снимается При извещении поток не получает управления пока не может получить блокировку обратно Псевдокод monitor.unlock() monitor.await() monitor.lock() Georgiy Korneev Java Advanced / Collections Framework 21 Производитель-потребитель (2) Установка значения public synchronized void set(Object data) throws InterruptedException { while (data != null) wait(); this.data = data; notify(); } Georgiy Korneev Java Advanced / Collections Framework 22 Производитель-потребитель (3) Получение значения public synchronized Object get() throws InterruptedException { while (data == null) wait(); Object d = data; data = null; notify(); return d; } Georgiy Korneev Java Advanced / Collections Framework 23 Часть 3 Модель памяти Java Основные свойства Атомарность Видимость Упорядоченность Georgiy Korneev Java Advanced / Collections Framework 25 Атомарность Атомарная операция выполняется как единое целое Операции над всеми типами кроме long и double являются атомарными Georgiy Korneev Java Advanced / Collections Framework 26 Пример int a = 0; long b = 0; a = 1; b = -1; Возможные значения a Возможные значения b Georgiy Korneev 0 1 0 -1 0xffffffff00000000 0x00000000ffffffff … Java Advanced / Collections Framework 27 Видимость Изменения произведенные потоком 1 видимы потоком 2 Видимость гарантируется в следующих случаях После изменений поток 1 освободил блокировку, которую захватил поток 2 После изменения поток 1 создал поток 2 Поток 2 дождался окончания потока 1 При неправильной синхронизации изменения могут быть видимы в произвольном порядке Georgiy Korneev Java Advanced / Collections Framework 28 Пример int a = 0; int b = 0; a = 1; b = 2; Возможные значения пары а, b Georgiy Korneev 0, 0 1, 0 1, 2 0, 2 Java Advanced / Collections Framework 29 Упорядоченность Программы выполняются как если бы они были написаны последовательно С точки зрения других потоков выполнение программы может производиться в произвольном порядке Georgiy Korneev Java Advanced / Collections Framework 30 Пример int a = 0; a = 1; a = 2; Возможные последовательност и значений а Georgiy Korneev 0, 0 0, 1 0, 2 1, 2 2, 0 2, 1 … Java Advanced / Collections Framework 31 Volatile-переменные Операции с volatile-переменными всегда атомарны При чтение значения volatile-переменной оно всегда читается из общей памяти При записи значения volatile-переменной оно всегда записывается в общую память Если volatile-ссылка изменилась, то данные доступные по ней могли не измениться Georgiy Korneev Java Advanced / Collections Framework 32 Пример volatile List l = null; t1() { List l = new ArrayList(); l.add(new Object()); this.l = l; } Georgiy Korneev Object t2() { while (l != null) { return l.get(0); } } Java Advanced / Collections Framework 33 Выводы При отсутствии правильной синхронизации потоки могут увидеть практически что угодно Georgiy Korneev Java Advanced / Collections Framework 34 Часть 4 Примеры Барьер public await(Barrier that) { // 0 synchronized (this) { // 1 this.generation++; // 2 this.notify(); // 3 } // 4 synchronized (that) { // 5 while (this.generation != that.generation) { // 6 that.wait(); // unlock 7, await 8, lock 9 } // 10 } // 11 } Georgiy Korneev Java Advanced / Collections Framework 36 Диаграмма переходов для барьера 0 1 2 3 4 5 6 7 8 9 10 11 2 2 2 1 1 1 1 0 1 2 3 4 5 6 7 8 9 10 11 Georgiy Korneev 1 1 1 2 2 2 2 Java Advanced / Collections Framework 37 Гарантированный deadlock public void run() { // 0 synchronized (o1) { // 1 o1.notifyAll(); // 2 synchronized (o2) { // 3 try { o2.wait(); // unlock 4, await 5, lock 6 } catch (InterruptedException e) {} } // 7 } // 8 } Georgiy Korneev Java Advanced / Collections Framework 38 Диаграмма переходов для deadlock 0 1 2 3 4 5 6 7 8 2 2 1,2 2 2 1,2 2 0 1 2 3 4 5 6 7 8 Georgiy Korneev 1 1 1,2 1 1 1,2 1 Java Advanced / Collections Framework 39 Часть 6 Заключение Выводы Программы должны быть хорошо синхронизированы Недосинхронизированные программы могут вести себя практически как угодно Пересенхронизированные программы часто страдают deadlock’ами Georgiy Korneev Java Advanced / Collections Framework 41 Ссылки JLS. Threads and Locks // http://java.sun.com/docs/books/jls/third_editio n/html/memory.html Threads: Doing Two or More Tasks At Once (Java Tutorial) // http://java.sun.com/docs/books/tutorial/essent ial/threads/index.html Georgiy Korneev Java Advanced / Collections Framework 42 Вопросы СПбГУ ИТМО Georgiy Korneev Java Advanced / Многопоточное программирование. Средства языка Java 43