← Назад к вопросам

Приведи пример синхронной коммуникации

1.0 Junior🔥 131 комментариев
#Docker, Kubernetes и DevOps

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Приведи пример синхронной коммуникации

Что такое синхронная коммуникация?

Синхронная коммуникация — это когда отправитель ждёт ответ перед тем, как продолжить работу:

Отправитель                    Получатель
   |                              |
   |--- Отправляю запрос -------> |
   |                              |
   | <---- Ожидаю ответ -------   | Обрабатываю
   |                              |
   | <---- Возвращаю ответ ------|
   |                              |
   |--- Продолжаю работу -------> |

Это как позвонить в поддержку — ты ждёшь, пока тебе ответят.

Пример 1: HTTP Request-Response (REST API)

Самый распространённый пример синхронной коммуникации в веб-приложениях:

import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

public class SyncHttpExample {
    public static void main(String[] args) throws Exception {
        HttpClient client = HttpClient.newHttpClient();
        
        // Создаём запрос
        HttpRequest request = HttpRequest.newBuilder()
            .uri(new URI("https://api.github.com/users/torvalds"))
            .GET()
            .build();
        
        // ✅ Синхронное ожидание ответа
        HttpResponse<String> response = client.send(request,
            HttpResponse.BodyHandlers.ofString());
        
        // Продолжаем работу только когда пришёл ответ
        System.out.println("Status: " + response.statusCode());
        System.out.println("Body: " + response.body());
    }
}

Поток выполнения:

1. Создаём запрос
2. Отправляем (блокируется здесь)
3. Ждём ответа от сервера
4. Получили ответ
5. Продолжаем (только здесь!)

Пример 2: Вызов метода в Spring

@RestController
@RequestMapping("/api")
public class UserController {
    private final UserService userService;
    
    @GetMapping("/users/{id}")
    public ResponseEntity<UserDTO> getUser(@PathVariable Long id) {
        // Синхронный вызов сервиса
        User user = userService.findById(id);  // ✅ Блокирует, ждёт результата
        
        // Только когда вернулся результат, продолжаем
        return ResponseEntity.ok(new UserDTO(user));
    }
}

@Service
public class UserService {
    private final UserRepository userRepository;
    
    public User findById(Long id) {
        return userRepository.findById(id)  // Запрос в БД
            .orElseThrow(() -> new NotFoundException("User not found"));
    }
}

Временная шкала:

HTTP запрос
   |
   v
getUser() вызывает userService.findById()
   |
   v
запрос в БД (SELECT)
   |
   v
Текущий поток БЛОКИРУЕТСЯ, ждёт ответа
   |
   v
Вернулись данные
   |
   v
Возвращаем HTTP 200 с данными

Пример 3: Синхронный вызов внешнего API

@Service
public class PaymentService {
    private final RestTemplate restTemplate;
    
    public void processPayment(Order order) {
        // Синхронный вызов платёжного API
        PaymentResponse response = restTemplate.postForObject(
            "https://payment.api/charge",
            new PaymentRequest(order.getAmount(), order.getCard()),
            PaymentResponse.class
        );
        
        // Здесь код выполняется ТОЛЬКО если пришёл ответ
        if (response.isSuccess()) {
            order.setStatus("PAID");
            logger.info("Payment processed for order " + order.getId());
        } else {
            throw new PaymentException("Payment failed: " + response.getError());
        }
    }
}

Проблема синхронности:

Обработка заказа
   |
   v
Вызов платёжного API (может быть медленно!)
   |
   v
Поток ЖДЁТ 1-5 секунд
   |
   v
Поток используется впустую (не обрабатывает другие запросы)
   |
   v
Ответ от API
   |
   v
Продолжаем обработку

Пример 4: JDBC и базы данных

public class UserDAO {
    
    // Синхронное получение данных из БД
    public User getUserById(Long id) {
        String sql = "SELECT * FROM users WHERE id = ?";
        
        try (Connection conn = dataSource.getConnection();
             PreparedStatement stmt = conn.prepareStatement(sql)) {
            
            stmt.setLong(1, id);
            
            // ✅ Синхронный запрос — блокируем поток
            ResultSet rs = stmt.executeQuery();
            
            if (rs.next()) {
                return new User(
                    rs.getLong("id"),
                    rs.getString("name"),
                    rs.getString("email")
                );
            }
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
        
        return null;
    }
}

Пример 5: Блокирующее чтение файла

public class FileExample {
    
    // Синхронное чтение файла
    public String readFile(String path) {
        try {
            // ✅ Поток блокируется, пока файл не прочитается
            byte[] data = Files.readAllBytes(Paths.get(path));
            return new String(data);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
    
    public static void main(String[] args) {
        FileExample example = new FileExample();
        
        // Поток ждёт завершения чтения
        String content = example.readFile("large_file.txt");
        
        // Только после этого продолжаем
        System.out.println("File size: " + content.length());
    }
}

Пример 6: Синхронный вызов микросервиса в Spring Boot

@Service
public class OrderService {
    private final RestTemplate restTemplate;
    private final UserServiceClient userClient;
    
    public Order createOrder(CreateOrderRequest request) {
        // Синхронный вызов микросервиса User Service
        UserDTO user = userClient.getUserById(request.getUserId());
        
        // Поток ждёт ответа от User Service
        if (user == null) {
            throw new UserNotFoundException("User not found");
        }
        
        // Синхронный вызов микросервиса Inventory Service
        InventoryDTO inventory = inventoryClient.checkStock(request.getProductId());
        
        // Снова ждём
        if (!inventory.isAvailable()) {
            throw new OutOfStockException("Product out of stock");
        }
        
        // Создаём заказ
        Order order = new Order();
        order.setUser(user);
        order.setProduct(request.getProductId());
        order.setStatus("CREATED");
        
        return orderRepository.save(order);
    }
}

@Component
public class UserServiceClient {
    private final RestTemplate restTemplate;
    
    public UserDTO getUserById(Long userId) {
        // Синхронный вызов с таймаутом 5 секунд
        return restTemplate.getForObject(
            "http://user-service/api/users/" + userId,
            UserDTO.class
        );
    }
}

Временная шкала создания заказа:

Поступил HTTP запрос
   |
   v
creatOrder() вызывает getUserById()
   |
   v
Отправляем запрос к User Service, БЛОКИРУЕМСЯ
   |
   v
Ожидание 100-500ms
   |
   v
Ответ от User Service
   |
   v
Вызываем inventoryClient.checkStock()
   |
   v
Отправляем запрос к Inventory Service, БЛОКИРУЕМСЯ
   |
   v
Ожидание 100-500ms
   |
   v
Ответ от Inventory Service
   |
   v
Сохраняем в БД
   |
   v
Возвращаем ответ (200-1000ms позже)

Проблемы синхронной коммуникации

// ❌ Проблема: один медленный сервис блокирует весь поток
public Order createOrder(CreateOrderRequest request) {
    // User Service: 100ms
    UserDTO user = userClient.getUserById(request.getUserId());
    
    // Inventory Service: 200ms
    InventoryDTO inventory = inventoryClient.checkStock(request.getProductId());
    
    // Payment Service: 2000ms (медленно!)
    PaymentDTO payment = paymentClient.charge(request.getPaymentInfo());
    
    // Итого: 2300ms на обработку одного заказа
    // За это время поток не может обрабатывать другие запросы!
}

Преимущества синхронной коммуникации

  1. Простота — легко писать и понимать код
  2. Надёжность — сразу видим результат или ошибку
  3. Транзакции — можно использовать ACID гарантии
  4. Отладка — просто ставим breakpoint и отлаживаем

Недостатки синхронной коммуникации

  1. Низкая масштабируемость — один медленный API блокирует весь поток
  2. Трудности в микросервисах — цепочка вызовов может быть медленной
  3. Зависимости — если целевой сервис упал, твой сервис тоже не работает
  4. Неэффективное использование ресурсов — потоки ждят вместо того, чтобы обрабатывать

Вывод

Синхронная коммуникация — это стандартный паттерн в веб-приложениях, который используется когда:

  • Нужен результат прямо сейчас
  • Нужны ACID гарантии
  • Простота важнее производительности

Для высоконагруженных систем используют асинхронную коммуникацию (message queues, event streaming).

Приведи пример синхронной коммуникации | PrepBro