26/08/2026

Многопоточность. Определения

курс stepic

Определения

Critical Section

Участок исполняемого кода программы, в котором производится доступ к общему ресурсу (данным или устройству), который не должен быть одновременно использован более чем одним потоком исполнения. Например, запись в файл, не должна производиться одновременно несколькими потоками.

Semaphore

Объект, ограничивающий количество потоков, которые могут войти в заданный участок кода. Внутри него есть счетчик и изначально в нем выставленно некое значение n.

init(n)
счетчик = n

У этого счетчика есть 2 метода enter() и leave().

  • enter() - ждать пока счетчик станет больше 0, после этого уменьшить на единицу

  • leave() - увеличить счетчик на единицу

Mutex

Простейший двоичный семафор, который может находиться в одном из двух состояний - отмеченном или неотмеченном (0 или 1). Это основа организации Critical Section.

Lock

Блокировка - это механизм синхронизации, позволяющий обеспечить исключительный доступ к разделяемому ресурсу между несколькими потоками. С помощью mutex'a подходя к некому участку кода проверяем можем ли мы туда зайти.

Мягкая блокировка - каждый поток пытается получить блокировку перед доступом к соответсвтующему разделяемому ресурсу

Обязательная блокировка - попытка несанкционированного доступа к заблокированному ресурсу будет прервана через создание исключения

Аппаратная поддержка: compare-and-swap

Monitor

Механизм взаимодействия и синхронизации процессов. Высокоуровневая конструкция, которая состоит из mutex'a, блокировки и массива ожидающих очереди потоков.

У монитора должен быть механизм остановки потока и сигнализации о доступности продолжения работы.

Executor

Это применение шаблона разделяющего создание сущности и ее использования. Разделяет создание Runnable и способ запуска run().

Executor нужен для тгго чтобы запустить на исполнение то что вы написали в Runnable, каким то образом позвать run().

Самый простой executor, который выполняет Runnable в том же потоке:

public class DirectExecutor implements Executor {

    @Override
    public void execute(Runnable r) {
        r.run();
    }
}

Либо executor, который выполняет Runnable в отдельном потоке:

public class ThreadPerTaskExecutor implements Executor {

    @Override
    public void execute(Runnable r) {
        new Thread(r).start();
    }
}

Callable

Runnable выполняет действия но не возвращает результат. Callable выполняет действие и возвращает результат.

  • через Runnable
TaskExtendedRunnable task = new TaskExtendedRunnable();
Thread t = new Thread(task);
t.start();
t.join();
String value = task.getSavedValue();
  • аналогично через Callable
ExecutorService pool = Executors.newFixedThreadPool(1);
Callable<Integer> callable = new TaskExtendedCallable();
Future<Integer> future = pool.submit(callable);
Integer value = future.get(); 

ExecutorService

Пулл потоков - Объект предоставляющий потоки.

ExecutorService pool = Executors.newFixedThreadPool(1);
Callable<Integer> callable = new TaskExtendedCallable();
Future<Integer> future = pool.submit(callable);

Future

Обертка над value, будет получено в будущем.

Future<Integer> future = pool.submit(callable);
future.get(); //блокировка до получения результата