Введение: что такое очередь задач в Java и зачем она нужна
В программировании часто возникает необходимость обрабатывать данные в порядке их поступления. Представьте себе очередь в кассу супермаркета: первый пришедший обслуживается первым. В Java эту логику реализует интерфейс Queue и его реализации. Очередь задач (Task Queue) — это структура данных, которая работает по принципу FIFO (First In, First Out — «первым пришёл, первым ушёл»).
Зачем это нужно? Очереди незаменимы при:
- Обработке запросов на сервере (веб-сервер, API)
- Буферизации данных перед записью в базу
- Реализации пула потоков (Thread Pool)
- Организации асинхронных задач
В этой статье мы разберём основные интерфейсы и классы для работы с очередями в Java, напишем простые примеры и дадим практические советы. Материал рассчитан на новичков, поэтому мы начнём с самых основ.
1. Интерфейс Queue и его базовые методы
В Java интерфейс java.util.Queue определяет основные операции для работы с очередью. Главные методы:
add(E e)— добавляет элемент в конец очереди. Если очередь заполнена, выбрасывает исключение.offer(E e)— добавляет элемент. В отличие отadd(), возвращаетfalseпри неудаче, а не исключение.remove()— удаляет и возвращает первый элемент. Если очередь пуста — исключениеNoSuchElementException.poll()— удаляет и возвращает первый элемент, илиnullесли очередь пуста.element()— возвращает первый элемент без удаления. Исключение при пустой очереди.peek()— возвращает первый элемент без удаления, илиnull.
Самая популярная реализация Queue — это LinkedList. Она проста и подходит для большинства базовых задач.
import java.util.LinkedList;
import java.util.Queue;
public class QueueExample {
public static void main(String[] args) {
// Создаём очередь строк
Queue<String> taskQueue = new LinkedList<>();
// Добавляем задачи (метод offer)
taskQueue.offer("Задача 1: Обработать заказ");
taskQueue.offer("Задача 2: Отправить email");
taskQueue.offer("Задача 3: Сформировать отчёт");
System.out.println("Очередь задач: " + taskQueue);
// Обрабатываем задачи по очереди
while (!taskQueue.isEmpty()) {
String task = taskQueue.poll(); // Берём первую задачу
System.out.println("Выполняется: " + task);
// Здесь можно написать логику выполнения
}
System.out.println("Все задачи выполнены. Очередь пуста: " + taskQueue.isEmpty());
}
}
Вывод программы:
Очередь задач: [Задача 1: Обработать заказ, Задача 2: Отправить email, Задача 3: Сформировать отчёт]
Выполняется: Задача 1: Обработать заказ
Выполняется: Задача 2: Отправить email
Выполняется: Задача 3: Сформировать отчёт
Все задачи выполнены. Очередь пуста: true
2. Deque — двунаправленная очередь
Интерфейс Deque (Double Ended Queue) расширяет Queue и позволяет работать с обоими концами очереди. Вы можете добавлять и удалять элементы как с начала, так и с конца. Это даёт больше гибкости.
Основные дополнительные методы:
addFirst() / offerFirst()— добавить в начало.addLast() / offerLast()— добавить в конец (аналогoffer()).removeFirst() / pollFirst()— удалить из начала.removeLast() / pollLast()— удалить из конца.getFirst() / peekFirst()— посмотреть первый элемент.getLast() / peekLast()— посмотреть последний элемент.
Реализации: ArrayDeque (быстрее, чем LinkedList) и LinkedList.
import java.util.Deque;
import java.util.ArrayDeque;
public class DequeExample {
public static void main(String[] args) {
Deque<String> deque = new ArrayDeque<>();
// Добавляем задачи в конец (как обычная очередь)
deque.offerLast("Задача A");
deque.offerLast("Задача B");
// Добавляем срочную задачу в начало
deque.offerFirst("Срочная задача!");
System.out.println("Текущая очередь: " + deque);
// Обрабатываем сначала срочную задачу
String urgentTask = deque.pollFirst();
System.out.println("Срочная: " + urgentTask);
// Затем остальные
String task = deque.pollFirst();
System.out.println("Обычная: " + task);
System.out.println("Оставшиеся: " + deque);
}
}
Вывод:
Текущая очередь: [Срочная задача!, Задача A, Задача B]
Срочная: Срочная задача!
Обычная: Задача A
Оставшиеся: [Задача B]
3. PriorityQueue — очередь с приоритетами
Иногда задачи нужно обрабатывать не в порядке поступления, а по их важности. Например, сначала обработать VIP-заказы, а потом обычные. Для этого существует PriorityQueue. Она автоматически сортирует элементы согласно заданному компаратору или естественному порядку (если элементы реализуют Comparable).
Важно: PriorityQueue не гарантирует порядок элементов при итерации, но гарантирует, что при вызове poll() будет возвращён элемент с наивысшим приоритетом (наименьший в случае естественного порядка).
import java.util.PriorityQueue;
import java.util.Queue;
public class PriorityQueueExample {
public static void main(String[] args) {
// Очередь с приоритетом (числа — меньший приоритет = выше)
Queue<Integer> priorityQueue = new PriorityQueue<>();
priorityQueue.offer(5);
priorityQueue.offer(1);
priorityQueue.offer(3);
priorityQueue.offer(2);
System.out.println("Очередь: " + priorityQueue); // Порядок может быть любым
// Извлекаем элементы — всегда наименьший
while (!priorityQueue.isEmpty()) {
System.out.println("Из