Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Что такое Thread Starvation
Thread Starvation (голодание потока) — это ситуация, когда один или несколько потоков не получают достаточно CPU времени для выполнения своей работы, потому что другие потоки постоянно захватывают ресурсы и не освобождают им время на выполнение.
Основные причины Thread Starvation
- Высокий приоритет у других потоков — потоки с высоким приоритетом могут вытеснять потоки с низким приоритетом
- Занятое ожидание (Busy Waiting) — поток занимает CPU в цикле ожидания
- Неправильная синхронизация — потоки ждут друг друга в deadlock-подобных ситуациях
- Ограниченные ресурсы — недостаточно потоков в пуле для обработки всех задач
Пример 1: Голодание из-за приоритета
public class ThreadStarvationExample {
public static void main(String[] args) {
// Высокоприоритетный поток
Thread highPriorityThread = new Thread(() -> {
while (true) {
System.out.println("High priority thread running");
// Этот поток постоянно занимает CPU
}
});
// Низкоприоритетный поток - может никогда не выполниться
Thread lowPriorityThread = new Thread(() -> {
System.out.println("Low priority thread - может никогда не вывести это");
});
highPriorityThread.setPriority(Thread.MAX_PRIORITY);
lowPriorityThread.setPriority(Thread.MIN_PRIORITY);
highPriorityThread.start();
lowPriorityThread.start();
}
}
Пример 2: Голодание из-за занятого ожидания
public class BusyWaitingExample {
private static volatile boolean flag = false;
public static void main(String[] args) throws InterruptedException {
Thread thread1 = new Thread(() -> {
// Занятое ожидание - поток постоянно проверяет переменную
while (!flag) {
// Busy waiting - тратит CPU впустую
Thread.yield();
}
System.out.println("Flag is true!");
});
Thread thread2 = new Thread(() -> {
try {
Thread.sleep(1000);
flag = true;
} catch (InterruptedException e) {
e.printStackTrace();
}
});
thread1.start();
thread2.start();
thread1.join();
thread2.join();
}
}
Правильное решение: Использование условных переменных
public class ProperWaitingExample {
private static final Object lock = new Object();
private static volatile boolean flag = false;
public static void main(String[] args) throws InterruptedException {
Thread thread1 = new Thread(() -> {
synchronized (lock) {
try {
// Поток ждёт, а не пытается активно проверить состояние
while (!flag) {
lock.wait(); // Отпускает lock и ждёт уведомления
}
System.out.println("Flag is true!");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
Thread thread2 = new Thread(() -> {
synchronized (lock) {
try {
Thread.sleep(1000);
flag = true;
lock.notifyAll(); // Уведомляет ожидающие потоки
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
thread1.start();
thread2.start();
thread1.join();
thread2.join();
}
}
Пример 3: Голодание в пуле потоков
import java.util.concurrent.*;
public class ThreadPoolStarvationExample {
public static void main(String[] args) {
// Создание пула с только одним потоком
ExecutorService executor = Executors.newFixedThreadPool(1);
// Задача 1 - берёт единственный поток
executor.submit(() -> {
try {
Thread.sleep(10000); // Длительная операция
System.out.println("Task 1 complete");
} catch (InterruptedException e) {
e.printStackTrace();
}
});
// Задача 2 - будет голодать, ожидая освобождения потока
executor.submit(() -> {
System.out.println("Task 2 - может долго ждать!");
});
executor.shutdown();
}
}
Правильное решение: Оптимальный размер пула
import java.util.concurrent.*;
public class OptimalThreadPoolExample {
public static void main(String[] args) {
// Оптимальный размер: количество ядер + 1 для I/O операций
int coreCount = Runtime.getRuntime().availableProcessors();
ExecutorService executor = Executors.newFixedThreadPool(coreCount + 1);
for (int i = 0; i < 100; i++) {
final int taskId = i;
executor.submit(() -> {
System.out.println("Task " + taskId + " executed");
});
}
executor.shutdown();
}
}
Как избежать Thread Starvation
- Избегай занятого ожидания — используй
wait(),notify(),Lock,Condition - Будь осторожен с приоритетами — не устанавливай крайние значения приоритетов
- Оптимизируй размер пула потоков — используй
Runtime.getRuntime().availableProcessors() - Избегай блокирующих операций — используй асинхронные операции, фьючеры
- Используй высокоуровневые инструменты —
CountDownLatch,CyclicBarrier,Phaser - Профилируй приложение — отслеживай использование потоков
Thread Starvation — критическая проблема в многопоточных приложениях, которая может привести к падению производительности и зависанию приложения.