Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
# Как блокировать вызов на сервере
Блокировка вызова на сервере — это остановка выполнения потока до наступления определённого события или условия. В Java есть несколько способов реализации, в зависимости от сценария.
1. Синхронизация через Lock и Condition
Это самый гибкий способ для блокировки потока в ожидании события:
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.Condition;
public class PaymentService {
private Lock lock = new ReentrantLock();
private Condition paymentProcessed = lock.newCondition();
private boolean isPaid = false;
// Поток ждёт платежа
public void waitForPayment() throws InterruptedException {
lock.lock();
try {
while (!isPaid) {
System.out.println("Ожидаю платежа...");
paymentProcessed.await(); // блокируем
}
System.out.println("Платёж получен!");
} finally {
lock.unlock();
}
}
// Другой поток сигнализирует завершение
public void processPayment() {
lock.lock();
try {
isPaid = true;
paymentProcessed.signalAll(); // разблокируем ожидающие потоки
System.out.println("Платёж обработан");
} finally {
lock.unlock();
}
}
}
// Использование
PaymentService service = new PaymentService();
Thread waiter = new Thread(() -> {
try {
service.waitForPayment();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
Thread processor = new Thread(() -> {
try {
Thread.sleep(2000);
service.processPayment();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
waiter.start();
processor.start();
2. CountDownLatch — блокировка до счётчика 0
Используется для блокировки одного или нескольких потоков до завершения операций:
import java.util.concurrent.CountDownLatch;
public class OrderService {
public void processOrder() {
int tasksCount = 3;
CountDownLatch latch = new CountDownLatch(tasksCount);
// Основной поток ждёт
Thread mainThread = new Thread(() -> {
try {
System.out.println("Начинаю обработку заказа...");
latch.await(); // блокируем до latch.countDown() 3 раза
System.out.println("Все задачи выполнены!");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
// Фоновые потоки для отдельных задач
for (int i = 1; i <= tasksCount; i++) {
final int taskId = i;
new Thread(() -> {
try {
Thread.sleep(1000 * taskId);
System.out.println("Задача " + taskId + " выполнена");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
latch.countDown(); // уменьшаем счётчик
}
}).start();
}
mainThread.start();
}
}
3. CyclicBarrier — блокировка до прихода всех потоков
Барьер, где потоки ждут друг друга:
import java.util.concurrent.CyclicBarrier;
public class RaceService {
public void startRace() {
int runners = 3;
CyclicBarrier barrier = new CyclicBarrier(runners, () -> {
System.out.println("=== СТАРТУЕМ! ===");
});
for (int i = 1; i <= runners; i++) {
final int runner = i;
new Thread(() -> {
try {
System.out.println("Бегун " + runner + " на линии старта");
barrier.await(); // ждём остальных
System.out.println("Бегун " + runner + " стартует!");
} catch (Exception e) {
Thread.currentThread().interrupt();
}
}).start();
}
}
}
4. Semaphore — ограничение доступа
Блокировка до освобождения ресурса:
import java.util.concurrent.Semaphore;
public class DatabaseConnectionPool {
private Semaphore semaphore;
public DatabaseConnectionPool(int maxConnections) {
this.semaphore = new Semaphore(maxConnections);
}
public void executeQuery(String query) throws InterruptedException {
semaphore.acquire(); // ждём свободного слота
try {
System.out.println("Выполняю: " + query);
Thread.sleep(2000); // имитация запроса
} finally {
System.out.println("Запрос завершён");
semaphore.release(); // освобождаем слот
}
}
}
// Использование
DatabaseConnectionPool pool = new DatabaseConnectionPool(2);
for (int i = 1; i <= 5; i++) {
final int id = i;
new Thread(() -> {
try {
pool.executeQuery("SELECT * FROM users where id=" + id);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}).start();
}
5. Future/CompletableFuture — асинхронная блокировка
Для асинхронных операций:
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ApiService {
private ExecutorService executor = Executors.newFixedThreadPool(2);
public void fetchData() {
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(3000);
return "Данные получены";
} catch (InterruptedException e) {
return "Ошибка";
}
}, executor);
// Блокируем главный поток до результата
String result = future.join(); // или future.get(5, TimeUnit.SECONDS)
System.out.println(result);
}
}
6. BlockingQueue — очередь с блокировкой
Для потокобезопасного обмена данными:
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
public class MessageService {
private BlockingQueue<String> queue = new LinkedBlockingQueue<>(10);
public void sendMessage(String msg) throws InterruptedException {
queue.put(msg); // ждёт, если очередь полна
}
public String receiveMessage() throws InterruptedException {
return queue.take(); // ждёт сообщения, если пусто
}
public void start() {
// Потребитель
new Thread(() -> {
try {
while (true) {
String msg = receiveMessage();
System.out.println("Получено: " + msg);
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}).start();
// Производитель
new Thread(() -> {
try {
for (int i = 1; i <= 10; i++) {
sendMessage("Сообщение " + i);
Thread.sleep(500);
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}).start();
}
}
7. synchronized — базовая синхронизация
Простейший способ, но менее гибкий:
public class Account {
private double balance = 1000;
public synchronized void withdraw(double amount) {
while (balance < amount) {
try {
wait(); // ждём депозита
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
balance -= amount;
System.out.println("Снял: " + amount);
}
public synchronized void deposit(double amount) {
balance += amount;
notifyAll(); // уведомляем ждущие потоки
System.out.println("Положил: " + amount);
}
}
Выбор подходящего механизма
| Ситуация | Механизм |
|---|---|
| Ждём события | Lock + Condition |
| Ждём завершения N задач | CountDownLatch |
| Синхронизация потоков | CyclicBarrier |
| Пул ресурсов | Semaphore |
| Асинхронные операции | CompletableFuture |
| Безопасный обмен | BlockingQueue |
| Простая синхронизация | synchronized |
Резюме
Блокировка вызова на сервере необходима для:
- Синхронизации потоков
- Ожидания внешних событий (БД, API, файлы)
- Управления ресурсами
- Обеспечения потокобезопасности
Выбор механизма зависит от конкретного сценария и требований к производительности.