Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
Форум программистов > Java: Общие вопросы > Прибить поток по таймауту |
Автор: yuliada 16.2.2009, 06:10 | ||||
Есть прога, которая проходится в цикле по файлам и вызывает для их обработки методы из некоторой либы, что именно происходит в которой неизвестно. Периодически эта либа виснет на случайном файле по неизвестным причинам. При повторном перезапуске на том же самом файле все отрабатывает ok. Решено было запускать либу в отдельном потоке, при достижении таймаута поток прибивать, пытаться повторить попытку еще пару раз (как правило на следующий раз сразу все ok) и затем переходить к следующему файлу. Для этого написала следующую штуку:
От нее потом наследовался класс, куда в run вставлялись те действия, с участием либы, которые приводили к вешанию проги. Запускалось это все вот так:
Прога успешно перелопачивает все файлы, но нормально не завершается, т.к. остаются висящие неприбытые потоки. Гуглить пробовала, как-то пока все туманно. Где неправильно? Что делать? Заранее спасибо ![]() |
Автор: Kirill89 16.2.2009, 10:31 |
мне кажется что при завершении обработки файла можно вызвать Thread.destroy |
Автор: ecologist 16.2.2009, 10:34 |
Надо сохранить ссылки на запущенные потоки и потом у каждого "недобитого" вызывать destroy. Хотя это варварский метод и считается некорректным. Надо, чтобы поток сам завершался. |
Автор: math64 16.2.2009, 10:37 |
Нужно вместо interrupt() вызывать stop() |
Автор: yuliada 16.2.2009, 18:34 |
Спасибо за ответы. Вот http://java.sun.com/j2se/1.3/docs/guide/misc/threadPrimitiveDeprecation.html говорят, что Thread.destroy has never been implemented. stop попробую, но на него везде очень много ругаются, не повлияет ли это на дальнейшую работу программы? К тому же по той же ссылке говорят, что It should be noted that in all situations where a waiting thread doesn't respond to Thread.interrupt, it wouldn't respond to Thread.stop either. |
Автор: serger 17.2.2009, 10:34 | ||
Это зависит от кода. Если вы не контролируите когда будет прерван код, то соответственно не можите гарантировать никакую операцию во время выполнения этого кода. Те любая из них может быть прервана. Получается, если при этом происходит работа с какими-нибудь ресурсами, или с другими частями программы, или планируется спонтанное увеличение функционала(что бывает практически всегда), или просто этот кусок кода вы неконтролируите или изменяется не только вами, в общем практически всегда, существует вероятность, что будет нарушена работы системы. Причём отловить в будущем такую ошибку будет очень сложно из-за слишком большого количества факторов к ней приводящих. |
Автор: x8m6 17.2.2009, 23:33 | ||
В методе run(), реализованном в классе FileProcessor, обязательно должен быть блок, перехватывающий прерывание потока. Что то типа того:
т.е. когда вы в методе runWithTimeout() вызываете innerThread.interrupt() поток лишь останавливается, но не уничтожается. При этом генерируется исключение типа InterruptedException. Если его обработаеть так , что поток будет выходить из run(), то в этом случае он будет гарантированно завершать свою работу и освобождать все занятые ресурсы. Если это не получится то сделайте все потоки демонами. В этом случае после обработки файлов потоки всё равно останутся сидеть в памяти, но прога будет успешно завершатся ![]() |
Автор: Kircul 18.2.2009, 12:24 | ||
Вот пример когда поток останавливается, и возобновляет работу:
Примерно вот так по моему надо делать... |
Автор: math64 18.2.2009, 13:05 |
Так надо делать если всё пишешь ты сам. А в данном случае используется чужая библиотека и кроме stop() ничего не остаётся делать. Альтернатива - запустить нить демоном из отдельной JVM. |
Автор: yuliada 19.2.2009, 02:03 |
Запустила со stop, работает так же как interrupt, то есть не помогает. Сегодня попробую совет x8m6. Попутно вопрос: в классе TimeoutRunner уже перехватывается InterruptedException, когда вызывается метод join(). Это тот же самый exception, который предлагается ловить в FileProcessor'e или нет? Просто сделать потоки демонами наверно не получится, потому что это обработка в последствии будет вызываться некоторой гуишкой, в которой после обработки что-то делается с результатами, поэтому эти потоки завершаться как я поняла только после завершения работы гуишки, а до этого будут висеть, что не есть наверное хорошо. Погуглю на счет того как запустить это из отдельной jvm. |
Автор: math64 19.2.2009, 09:29 | ||
да, TimeOutRunner уже ловит Exception (InterruptedException extends Exception)
|
Автор: x8m6 19.2.2009, 15:49 | ||
Не совсем тот же самый. Хоть они и из одно класса , но происходят в разное время. Первое исключение (в методе join(timeout)) может возникнуть тогда, когда главный поток засыпает на timeout - миллисекунд , в то время как innerthread работает с либой. При этом вы щё не знаете завис ли он на ком нибудь фаиле или нет. Если в это время по каким то причинам возникает исключение типа InterruptedException оно будет обработано в этом же методе runWithTimeout() , так как вы сделали. После прошествия timeout - миллисекунд и в случае, если innerthread продолжает работать, вы уже знаете что поток завис на каком то фаиле и сами иницируете 2-ое исключение вызовом метода innerThread.interrupt(). Оно возникнет в методе run() и там должно быть обработано. Не забудте убрать throws Exception в обявлении метода run(). |
Автор: math64 19.2.2009, 16:26 | ||
innerThread инициализируется так:
так что в run() дополнительный try { } catch() {} не нужен |
Автор: nitzshe 25.2.2009, 12:55 |
Использование stop тоже не выход: http://java.sun.com/j2se/1.5.0/docs/guide/misc/threadPrimitiveDeprecation.html "Why Are Thread.stop, Thread.suspend, Thread.resume and Runtime.runFinalizersOnExit Deprecated?" |
Автор: yuliada 27.2.2009, 12:04 |
Всем спасибо за советы, пока есть много что еще делать другого, поэтому поэкспериментирую с запуском из отдельной jvm попозже и отпишусь о результатах ![]() |
Автор: Vermut 27.2.2009, 23:19 | ||
Особого рилтайма не наблюдается так почему бы весь этот глючный код на отдельной JVM не запустить? через Runtime.exeс(args), у вас TimeLimit на один файл 120 секунд, время на запуск JVM много меньше. Собственно плюсы: - Когда запущенная JVM(камера пыток) закроется, операционная система утилизирует и незакрытые повисшими потоками файловые дескрипторы. - Если либа такая глючная, то лучше её изолировать от общества не в отдельных потоках окруженных try/catch или снабженных обработчиком uncaughtException, а в другом процессе(адресном пространстве), я б прежде чем её запускать, вообще бы бэкап исходных файлов на всякий случай делал. А любое использование либы в одной JVM с вашим приложением приведет к снижению его производительности, потому как она своими номерами поставит в тупик любой оптимизатор времени выполнения. Мало ли какие ресурсы помимо файлов эта либа удерживает: память, блокировки, а может она внутри себя трэды запускает тогда вообще пиши пропало. |
Автор: Vermut 28.2.2009, 22:45 |
Да не побьют меня модераторы ![]() Я сейчас винраром файл 7.5Gb распаковывал, ушло 8 с половиной минут. Вспомнил о вас. Собственно говоря вспомнил, что вы жестко таймаут задаёте. Рекомендую задавать его эмпирически на основе FileSize. |
Автор: yuliada 24.3.2009, 04:38 | ||
Переписала с запуском отдельной jvm, работает. Может пригодится кому как это написать примерно:
|