Java Advanced Многопоточное программирование Краткое содержание 1. Введение 2. Классические задачи многопоточного программирования 3. Атомарные операции 4. Примитивы синхронизации 5. Решения задач многопоточного программирования 6. Заключение Georgiy Korneev 2 Часть 1 Введение Многопоточное программирование Программа одновременно имеет несколько потоков исполнения Потоки должны взаимодействовать (синхронизироваться) друг с другом Georgiy Korneev 4 Пример. Умножение матриц // Матрицы размера n на n double[][] a, b, c; for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { c[i][j] = 0; for (int k = 0; k < n; k++) { c[i][j] += a[i][k] * b[k][j]; } } } Georgiy Korneev 5 Пример. Итеративный параллелизм // Матрицы размера n на n double[][] a, b, c; for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { c[i][j] = 0; for (int k = 0; k < n; k++) { c[i][j] += a[i][k] * b[k][j]; } } } Georgiy Korneev // Параллельно // Параллельно 6 Пример. Обмен сообщениями (1) Рабочий поток Worker[i] { double[] a; // a[i][*] double[][] b; // b[*][*] double[] c; // c[i][*] receive a, b from coordinator; for (int j = 0; j < n; j++) { c[j] = 0; for (int k = 0; k < n; k++) { c[j] += a[k] * b[k][j]; } } send c to coordinator; } Georgiy Korneev 7 Пример. Обмен сообщениями (2) Управляющий поток coordinator(int i) { double[][] a, b, c; for (int i = 0; i < n; i++) { send a[i], b to worker[i]; } for (int i = 0; i < n; i++) { receive c[i] from worker[i]; } } Georgiy Korneev 8 Пример. Обмен сообщениями (3) worker[i] { double[] a; // a[i][*] double[] b; // b[*][i] double[] c; // a[i][*] receive a, b from coordinator; for (int j = 0; j < n; j++) { double s = 0; for (int k = 0; k < n; k++) { s += a[k] * b[k]; } c[(i + j) % n] = s; send b to worker[(i + 1) % n]; receive b from worker[(i + n - 1) % n]; } send c to coordinator; } Georgiy Korneev 9 Пример. Вычисление интеграла Адаптивное вычисление интеграла f(x) double integrate(double l, double r) { if (abs(area(l, m) + area(m, r) - area(l, r)) > EPS) { return integrate(l, m) + integrate(m, r); } else { return area(l, m) + area(m, r); } } double area(double l, double r) { return (f(l) + f(r)) * (r - l) / 2; } Georgiy Korneev 10 Пример. Рекурсивный параллелизм Адаптивное вычисление интеграла f(x) double integrate(double l, double r) { double m = (l + r) / 2; double la = area(l, m); double ra = aread(m, r); if (abs(la + ra - area(l, r)) > EPS) { la = integrate(l, m); // Параллельно ra = integrate(m, r); // Параллельно } return la + ra; } Georgiy Korneev 11 Основные операции Создание потока Уничтожение потока Неделимая операция statements Неделимая операция с ожиданием условия await(C) statements Georgiy Korneev 12 Пример. Поиск максимума (1) Без синхронизации int max = 0; create worker[i] { if (max < a[i]) max = a[i]; } С синхронизацией int max = 0; create worker[i] { if (max < a[i]) max = a[i]; } Georgiy Korneev 13 Пример. Поиск максимума (2) Протокол Проверить-ПроверитьУстановить int max = 0; create worker[i] { if (max < a[i]) { if (max < a[i]) max = a[i]; } } Georgiy Korneev 14 Свойства планирования Справедливость Безусловная Слабая Сильная Безопасность Живучесть Georgiy Korneev 15 Часть 2 Классические задачи многопоточного программирования Задача доступа к общему ресурсу Несколько потоков обращаются к общему ресурсу T2 T1 Georgiy Korneev T3 R T4 T5 17 Производитель-потребитель Один поток производит данные, второй их потребляет Несколько потоков производят данные и несколько их потребляют Данные могут храниться в очереди (не)ограниченного объема P Georgiy Korneev Data C 18 Задача о читателях и писателях Читать могут много потоков одновременно Писать может только один поток Читать во время записи нельзя W1 R1 Data WN Georgiy Korneev RN 19 Задача об обедающих философах 5 Философов, 5 тарелок, 5 вилок Философ Думает Ест Что бы есть нужны обе вилки Georgiy Korneev 20 Задания-работники Поток-клиент ждет выполнения задания потоком-сервером C1 W1 Queue CN Georgiy Korneev WN 21 Часть 3 Атомарные операции Атомарная операция Операция выполняемая как единое целое Чтение Запись Неатомарные операции Инкремент Декремент Georgiy Korneev 23 Виды атомарных операций Операция чтения Операция записи set Операции записи и чтения get addAndGet, incAndGet, … getAndAdd, getAndInc, … Операция условной записи compareAndSet Georgiy Korneev 24 Решение задачи доступа к ресурсу // Получение доступа к ресурсу while(!v.compareAndSet(0, 1)); // Действия с ресурсом // Освобождение ресурса v.set(0); Georgiy Korneev 25 Часть 4 Примитивы синхронизации Критическая секция Только один поток может выполнять действия в критической секции Именованные критические секции < name: statements > Georgiy Korneev 27 Решение задачи доступа к ресурсу Доступ производится в критической секции resource < resource: // Доступ к ресурсу > Georgiy Korneev 28 Реализации критических секций На основе блокировки await(!lock) lock = true; // Критическая секция lock = false; // Вход // Выход На основе атомарных операций while(!lock.compareAndSet(0, 1)); // Критическая секция lock.set(0); Georgiy Korneev // Вход // Выход 29 Блокировка (lock, mutex) Только один поток может владеть блокировкой Могут быть использованы для передачи событий Операции lock unlock tryLock Georgiy Korneev получить блокировку отдать блокировку попробовать получить блокировку 30 Решение задачи доступа к ресурсу Доступ ограничен блокировкой lock // Получение блокировки lock.lock(); // Доступ к ресурсу // Освобождение блокировки lock.unlock() Georgiy Korneev 31 Семафор Хранит количество разрешений на вход Могут быть использованы для передачи событий Операции acquire получить разрешение release добавить разрешение tryAcquire попробовать получить разрешение Georgiy Korneev 32 Барьер Потоки блокируются пока все потоки не прибудут к барьеру Одноразовый Многоразовый Операции arrive прибытие к барьеру Georgiy Korneev 33 Монитор Разделяемые переменные инкапсулированы в мониторе Код в мониторе исполняется не более чем одним потоком Условия Операции с условиями wait ожидание условия notify сообщение об условии одному потоку notifyAll сообщение об условии всем потокам Georgiy Korneev 34 Часть 5 Решение классических задач параллельного программирования Производитель-потребитель Решение с помощью разделенных блокировок Производитель empty.lock(); // копирование full.unlock(); Потребитель full.lock(); // копирование empty.unlock(); Georgiy Korneev 36 Задания-работники Решение с помощью монитора Задание queue.add(task); queue.notify(); task.wait(); Работник while (queue.isEmpty()) queue.wait(); Task t = queue.get(); // Обработка задания t.notify(); Georgiy Korneev 37 Задача об обедающих философах Решение с помощью асимметрии Все философы кроме одного берут сначала левую, затем правую вилку Оставшийся философ берет сначала правую, затем левую вилку Georgiy Korneev 38 Задача о читателях и писателях (1) Решение с помощью блокировки Читатель if (nr++ == 0) busy.lock(); // Чтение if (--nr == 0) busy.unlock(); Писатель busy.lock(); // Запись busy.unlock(); Georgiy Korneev 39 Задача о читателях и писателях (2) Решение с помощью передачи эстафеты Особенности решения Если есть и писатели и читатели, то вход закрывается Пока есть читатели – разрешать чтение Когда нет читателей – разрешить запись Когда нет ни читателей ни писателей – открыть вход Georgiy Korneev 40 Задача о читателях и писателях (3) e dr dw r w nr nw Data e Georgiy Korneev 41 Задача о читателях и писателях Передача эстафеты if (nw == 0 && dr > 0) { dr--; r.unlock(); // Возобновить процесс-читатель } else if (nr == 0 && nw == 0 && dw > 0) { dw--; w.unlock(); // Возобновить процесс-писатель } else { e.unlock(); // Открыть вход } Georgiy Korneev 42 Задача о читателях и писателях Читатель e.lock(); if (nw > 0) { dr++; e.unlock(); r.lock(); } // Доступ разрешен nr++; // Передача эстафеты // Чтение e.lock(); nr--; // Передача эстафеты Georgiy Korneev 43 Задача о читателях и писателях Писатель e.lock(); if (nw > 0 || nr > 0) { dw++; e.unlock(); w.lock(); } nw++; // Передача эстафеты // Запись e.lock(); nw--; // Передача эстафеты Georgiy Korneev 44 Часть 6 Заключение Ссылки Эндрюс Г. Основы многопоточного, параллельного и распределенного программирования Lea D. Concurrent Programming in Java Garg V. Concurrent and Distributed Computing in Java Georgiy Korneev 46 Вопросы Georgiy Korneev 47