Технологии Java

Задачи и средства многопоточного программирования

Классические задачи

Содержание

Задача доступа к общему ресурсу

  • Несколько потоков обращаются к общему ресурсу

Производитель-потребитель

  • Несколько потоков производят данные
  • Несколько потоков потребляют данные
  • Данные могут храниться в очереди (не)ограниченного объема

Задача о читателях и писателях

  • Читать могут много потоков одновременно
  • Писать может только один поток
  • Читать во время записи нельзя

Задача об обедающих философах

  • n философов, n тарелок и n вилок
  • Философ либо думает, либо ест
  • Чтобы есть нужны две вилки

Задания и работники

  • Поток-клиент ждет выполнения задания потоком-сервером

Атомарные операции

Содержание

Теория

Содержание

Атомарная операция

  • Операция выполняемая как единое целое
    • Чтение
    • Запись
  • Неатомарные операции
    • Инкремент
    • Декремент

Виды атомарных операций

  • Чтение
    • get
  • Запись
    • set
  • Чтение и запись
    • getAndSet
  • Условная запись
    • compareAndSet

Условная запись

  • compareAndSet(old, new)
    • Если текущее значение равно old
    • Записать значение new
  • Идиома
    do {
        oldV = v.get();
        newV = process(old);
    } while (!v.compareAndSet(oldV, newV));
    

Решение задачи доступа к ресурсу

  • На основе атомарных операций
    // Получение доступа к ресурсу
    while (!v.compareAndSet(0, 1));
    // Действия с ресурсом
    // Освобождение ресурса
    v.set(0);
    

Практика

Содержание

Общие операции

Операции над числами

Атомарные переменные

Атомарные массивы

Атомарный доступ к полям

Сбор статистики

Помеченные ссылки

Содержание

Программ. транзакционная память

  • Программные транзакции
    • Локализация обновлений
    • Персистентные структуры данных
    • Атомарное обновление результата
  • Свойства
    • Первый — выигрывает
    • Проблема ABA

Помеченные ссылки

Операции

Блокировка

  • Только один поток может владеть блокировкой
  • Операции
    • lock – получить блокировку
    • unlock – отдать блокировку
    • tryLock – попробовать получить блокировку

Блокировки в Java

  • Интерфейс Lock
    • Пакет java.util.concurrent.locks
  • Методы
  • Передача событий

Условия

Производитель

  • Решение с помощью событий
    • void set(Object data) throws InterruptedException {
          lock.lock();
          try {
              while (this.data != null) {
                  notFull.await();
              }
              this.data = data;
              notEmpty.signal();
          } finally {
              lock.unlock();
          }
      }
      

Особенности

  • Отсутствие «блочности»
    • Необходимость явного отпускания
  • Идиома
    l.lock()
    try {
        …
    } finally {
        l.unlock()
    }
    

Производитель-потребитель

  • Решение с помощью разделенных блокировок
    • Производитель
      empty.lock();
      // копирование
      full.unlock();
      
    • Потребитель
      full.lock();
      // копирование
      empty.unlock();
      
  • Не поддерживается текущей реализацией

Реализация блокировки

Читатели и писатели

Критическая секция

  • Только один поток может выполнять действия в критической секции
  • Именованные критические секции
    〈name: statements〉
    

Решение задачи доступа к ресурсу

  • Доступ производится в критической секции
    resource
    〈
        resource:
        // Доступ к ресурсу
    〉
    

Реализации критических секций

  • На основе неделимых операций
    〈await(!lock) lock = true;〉 // Вход
    // Критическая секция
    lock = false; // Выход
    
  • На основе атомарных операций
    while (!lock.compareAndSet(0, 1));   // Вход
    // Критическая секция
    lock.set(0);    // Выход
    

Семафор

  • Хранит количество разрешений на вход
  • Операции
    • acquire — получить разрешение
    • release — добавить разрешение
  • Доступ к ограниченным ресурсам

Реализация семафора

  • С применением атомарных операций
    • Получение разрешения
      do {
          do {
              p = permits.get();
          } while (p == 0);
      } while (!permits.compareAndSet(p, p - 1));
      
    • Добавление разрешения
      do {
          p = permits.get();
      } while (!permits.compareAndSet(p, p + 1));
      

Семафоры в Java

Барьер

  • Потоки блокируются пока все потоки не прибудут к барьеру
    • Одноразовый
    • Многоразовый
  • Операции
    • arrive — прибытие к барьеру
  • Синхронизация потоков
    • Переход к следующему этапу

Барьеры в Java

  • Конструкторы
  • Методы
    • await(time?, unit?) – барьер.
    • reset() – возвращает барьер в исходное состояние
    • isBroken() – «сломан» ли барьер
    • статистика

Защелки

  • Ожидание завершения нескольких действий
  • Операции
    • countDown() – опускает защелку на единицу
    • await() – ждет спуска защелки

Защелки в Java

  • Конструктор
  • Методы
  • Применение
    • Инициализация

Phaser

Рандеву

Решение классических задач

Содержание

Простые задачи

Содержание

Задания-работники

  • Решение с помощью монитора
    • Задание
      queue.add(task);
      queue.notify();
      task.wait();
      
    • Работник
      while (queue.isEmpty()) {
          queue.wait();
      }
      Task t = queue.get();
      // Обработка задания
      t.notify();
      

Задача об обедающих философах

  • Решение с помощью асимметрии
    • Все философы кроме одного берут сначала левую, затем правую вилку
    • Оставшийся философ берет сначала правую, затем левую вилку

Задача о читателях и писателях

Содержание

Решение с помощью блокировки

  • Читатель
    〈if (nr++ == 0) busy.lock();〉
    // Чтение
    〈if (--nr == 0) busy.unlock();〉
    
  • Писатель
    busy.lock();
    // Запись
    busy.unlock();
    

Решение с накопителем

Накопители и передача эстафеты

  • Если есть и писатели, и читатели, то вход закрывается
  • Пока есть читатели – разрешать чтение
  • Когда нет читателей – разрешить запись
  • Когда нет ни читателей, ни писателей – открыть вход

Задача о читателях и писателях

  • Передача эстафеты
    if (nw == 0 && dr > 0) {
        dr--;
        // Возобновить процесс-читатель
        r.unlock();
    } else if (nr == 0 && nw == 0 && dw > 0) {
        dw--;
        // Возобновить процесс-писатель
        w.unlock();
    } else {
        e.unlock(); // Открыть вход
    }
    

Задача о читателях и писателях

  • Читатель
    e.lock();
    if (nw > 0) { dr++; e.unlock(); r.lock(); }
    // Доступ разрешен
    nr++;
    // Передача эстафеты
    // Чтение
    e.lock();
    nr--;
    // Передача эстафеты
    

Задача о читателях и писателях

  • Писатель
    e.lock();
    if (nw > 0 || nr > 0) { dw++; e.unlock(); w.lock(); }
    nw++;
    // Передача эстафеты
    // Запись
    e.lock();
    nw--;
    // Передача эстафеты
    

Заключение

Содержание

Ссылки

Вопросы