Один поток задаёт свойство прокси, выполняет запрос и восстанавливает прежнее значение. Другой поток делает то же самое с другим прокси. При чтении сверху вниз код выглядит аккуратно, но оба потока меняют общее состояние JVM.

System.setProperty() меняет системное свойство процесса. Оно не привязывает маршрут к потоку, который его вызвал. Параллельный запрос может увидеть значение, записанное для чужой работы, а существующий клиент, возможно, уже зафиксировал собственную конфигурацию.

Сделайте маршрут частью клиента

Для HTTP-клиента Java создавайте клиентов с осознанными селекторами прокси. Держите отдельные клиенты, когда нагрузкам нужны разные политики маршрутизации:

HttpClient client = HttpClient.newBuilder()
    .proxy(ProxySelector.of(
        new InetSocketAddress("203.0.113.10", 8080)))
    .connectTimeout(Duration.ofSeconds(5))
    .build();

Импорты — java.net, java.net.http и java.time. Адрес приведён для примера; для разрешённых проверок публичных маршрутов список HTTP-прокси даёт подходящие конечные точки. Настройте сроки запросов и аутентификацию прокси отдельно, исходя из нужд приложения.

Метод proxy у builder фиксирует выбор на уровне клиента. Поэтому политику проще проверить, чем последовательность глобальных записей вокруг асинхронных операций.

Глобальные настройки всё ещё нужны

Единая политика прокси для всей JVM может подойти, если каждый участвующий клиент должен ей следовать. Задайте эту политику при запуске приложения и проверьте, какие библиотеки её соблюдают.

Проблемы возникают, когда глобальные свойства используют как временный переключатель для отдельных запросов. На сервере фоновые обработчики и вызовы библиотек могут работать одновременно, даже если ваш метод выглядит синхронным. Храните состояние маршрутизации в клиенте или коннекторе, которому принадлежит соединение, чтобы другой запрос не мог изменить его посреди работы.

Похожие статьи