Skip to content

Latest commit

 

History

History
150 lines (111 loc) · 6.98 KB

File metadata and controls

150 lines (111 loc) · 6.98 KB

IPriorityExecutorService

Обстоятельство

  • Задачи должны выполняться асинхронно.
  • Задачи должны выполняться на основе их приоритета, а не порядка их поступления.

Использование

Интерфейс IPriorityExecutorService расширяет java.util.concurrent.ExecutorService и предоставляет возможность асинхронной обработки задач на основе их приоритета, а не порядка их поступления. Если задачи имеют одинаковый приоритет, они будут обработаны в порядке поступления.

Использование IPriorityExecutorService ничем не отличается от использования java.util.concurrent.ExecutorService. Для постановки задач в очередь на исполнение используйте привычные методы execute(), submit() и т.д. Особенность лишь в способе определения приоритета задач, о чем будет сказано ниже.

Создание исполнителя

Самый простой способ создания IPriorityExecutorService - использовать фабричные методы IExecutorFactory.newPrioritySingleThreadExecutor() или IExecutorFactory.newPriorityFixedThreadPool().

IPriorityExecutorService priorityExecutor = Asynchronizer.executorFactory()
        .newPrioritySingleThreadExecutor(getClass());

Созданный таким образом исполнитель будет учитывать асинхронный контекст.

Более прямолинейный способ создания IPriorityExecutorService - создание экземпляра класса PriorityExecutorService, используя его конструктор.

int poolSize;
ThreadFactory threadFactory;
...
IPriorityExecutorService priorityExecutor = new PriorityExecutorService(poolSize, threadFactory);

Приоритизация задач

Приоритет задачи можно указать явно и неявно.

Явное указание приоритета

Задача должна реализовать интерфейс IPriorityTask, явно определив его метод priority(). Этот метод возвращает числовое значение приоритета: чем больше число, тем больше приоритет у задачи.

Для удобства созданы два расширения интерфейса IPriorityTask:

Интерфейс IPriorityRunnable используется для тех задач, которые не возвращают результат своей работы, а интерфейс IPriorityCallable для тех, которые возвращают.

Задача реализует интерфейс IPriorityTask явно, если она должна инкапсулировать логику вычисления приоритета.

class MyRunnableTask implements IPriorityRunnable {

    @Override
    public int priority() {
        // Вычисление приоритета
    }

    @Override
    public void run() {
        // Реализация задачи
    }
}

class MyCallableTask implements IPriorityCallable<String> {

    @Override
    public int priority() {
        // Вычисление приоритета
    }

    @Override
    public String call() {
        // Реализация задачи
    }
}

Если приоритет задачи определяется извне и есть необходимость типизировать задачи, определение задач можно немного упростить, используя record.

record MyRunnableTask(int priority) implements IPriorityRunnable {

    @Override
    public void run() {
        // Реализация задачи
        System.out.println("Привет!");
    }
}

record MyCallableTask(int priority) implements IPriorityCallable<String> {

    @Override
    public String call() {
        // Реализация задачи
        return "Привет!";
    }
}

Самый простой способ определить приоритет - воспользоваться одним из методов with(), указав приоритет и реализацию задачи.

var myRunnableTask = IPriorityRunnable.withPriority(priority, () -> {
    // Реализация задачи
    System.out.println("Привет!");
});

var myCallableTask = IPriorityCallable.withPriority(priority, () -> {
    // Реализация задачи
    return "Привет!";
});

Создав задачу, ее можно передать на исполнение как обычно.

IPriorityExecutorService priorityExecutor;
...
priorityExecutor.execute(myRunnableTask);
priorityExecutor.submit(myCallableTask);

Неявное указание приоритета

Если задачи поступают извне и имеют один и тот же приоритет, можно сразу определить исполнитель с этим уровнем приоритета и все задачи с таким приоритетом делегировать ему. Для этого можно воспользоваться одним из методов IPriorityExecutorService.with().

IPriorityExecutorService priorityExecutor;
...
ExecutorService priority42Executor = priorityExecutor.withPriority(42);
ExecutorService lowPriorityExecutor = priorityExecutor.withLowPriority();
ExecutorService highPriorityExecutor = priorityExecutor.withHighPriority();
...
lowPriorityExecutor.execute(() -> System.out.println("Low priority task"));
highPriorityExecutor.execute(() -> System.out.println("High priority task"));

Удобство и основное преимущество такого подхода в том, что источник задач не отвечает за их приоритизацию.