#java #loops #concurrency
#java #циклы #параллелизм
Вопрос:
У меня есть поток, в котором у меня есть бесконечный цикл, выполняющий некоторые сетевые операции. Похоже, что я не получаю ответа каждый раз, когда делаю это, поэтому поток зависает на несколько секунд, что вызывает серьезные проблемы с моим программным обеспечением. Что мне нужно, так это какой-то «крайний срок» для цикла, если это займет больше времени (например, 100 мс), перезапустите снова.
private boolean active = true;
public void run(){
while(active){
//some network stuff e.g:
dnshandler.reverselookup("8.8.8.8");
}
}
(это не настоящий класс… это просто для того, чтобы получить представление о том, что я имею в виду.)
Есть идеи, как с этим справиться?
Обновление: я обработал его отдельным потоком, как было предложено. На самом деле я использовал вызываемый, потому что мне нужно возвращаемое значение.
ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
try {
List<Future<String>> results = executor.invokeAll(Arrays.asList(new CallableClass()), 500), TimeUnit.MILLISECONDS);
for (Future<String> current : results) {
if (!current.isCancelled()) {
someValue = current.get();
} else {
// timeout
executor.shutdownNow();
}
}
} catch (Exception e) {
//handle it!
e.printStackTrace();
}
Но проблема, с которой я сталкиваюсь сейчас, заключается в том, что executor.shutdownNow()
не завершается зависающая вызываемая задача (что является правильным поведением в соответствии с документацией). Есть ли способ завершить задачу исполнителя? (Я знаю, что это не чистое решение, но некоторые запросы обрабатываются библиотекой)
Ответ №1:
Вы можете поместить свои сетевые материалы в отдельный поток и запустить его, например, на пару секунд:
int timeoutTime = ...
Runnable networkingStuff = ... // put the networking in here
Thread thread =new Thread(networkingStuff);
thread.start();
try {
thread.join(timeoutTime);
if(thread.isAlive()) {
thread.interrupt();
}
} catch (InterruptedException e) {
// catch here the interruption
}
Комментарии:
1. Я не думал о join, это могло бы сработать. Просто для подтверждения, если «сетевой поток» завершается в
timeoutTime
я в конечном итоге попадаю в часть try блока try-catch, else в catch. В любом случае мой бесконечный цикл продолжается?2. Вы попадаете в блок catch, если поток прерывается ненормально. Это не должно происходить в нормальных рабочих условиях. Вы всегда должны заканчиваться в «if (thread.IsAlive())» при nprmal условиях. Если поток завершился сам по себе, то thread.IsAlive() == false. Если он все еще выполняется после истечения времени ожидания, то thread.IsAlive() == true и вы завершаете поток с помощью thread.interrupt(). В вашем бесконечном цикле вы должны проверить наличие Thread.interrrupted() == true. Если это так, вы должны завершить цикл, вызвав break или установив переменную, которая проверяется в условиях цикла.
3. Хорошо, спасибо. Я реализовал это так, как вы предполагали, и это работает локально. Я добавлю это в следующий тестовый выпуск и сообщу вам, как это сработало при полной загрузке. Спасибо!
Ответ №2:
TimeLimiter от Google Guava может сделать то, что вам нужно.
[TimeLimiter] создает прокси, которые накладывают ограничение по времени на вызовы методов к проксируемому объекту.
Ответ №3:
Прошу прощения, если это неправильно, поскольку я не разработчик Java, но с общей точки зрения программирования у вас должен быть свой метод, который может потребовать времени, возвращающий некоторую форму TimeoutException
.
Вы можете перехватить это в своем цикле, и тогда он автоматически перезапустится.
Это проблема не с циклом, а скорее с методами, которые вы вызываете внутри.
Альтернативным подходом было бы выполнение ваших трудоемких операций в отдельном потоке, чтобы ничего не зависало. Затем вы можете уведомить основной поток (пользовательский интерфейс) о завершении в любое время.
Комментарии:
1. Я думал о том, чтобы запускать поток каждый раз, когда я вызываю трудоемкие методы, потому что это своего рода стандартный подход для обработки блокирующих функций. Но я немного боюсь запускать несколько сотен потоков в секунду, или это не проблема? В любом случае, я рассмотрю подход TimeoutException и сообщу об этом. Спасибо 🙂
2. Вы, вполне возможно, столкнулись бы с падением производительности, пока потоки создаются, да. Лучшей идеей было бы просто иметь весь цикл в вашем потоке, а не операцию.
3. Весь цикл уже находится в отдельном потоке. У меня есть поток-производитель и несколько потоков-потребителей. Упомянутый поток является потоком-потребителем. Проблемы возникают, если все потоки-потребители зависают из-за отсутствия ответа, это приводит к исключению нехватки памяти (которого можно избежать, используя меньший буфер между производителем или потребителем ( —> приводит к потере данных, поскольку производитель не может произвести) или увеличению размера кучи, что скорее является обходным решением и приводит к другим проблемам). Я все еще пытаюсь поймать
TimeoutException
… позже опубликую свой прогресс.4. Справедливо, извините, я не смог быть более конкретным или предоставить какой-либо код — как я уже сказал, не разработчик Java, просто пытаюсь помочь! ^_^
Ответ №4:
Ваш бесконечный цикл while загружает процессор. Попробуйте добавить задержку в 50 мс или около того, чтобы дать небольшой перерыв процессору для решения других задач. А еще лучше, запланируйте выполнение своей задачи с помощью Timer
с определенной задержкой и TimerTask
.
Ответ №5:
Вы должны прервать поток после истечения времени ожидания. Ознакомьтесь с руководством по java concurrency.