2013-02-13 4 views
0

Я делаю простой сервер, который будет генерировать несколько потоков для обработки нескольких клиентов. Мне было интересно, как закрыть и закрыть все потоки и потоки при завершении работы сервера.Java: Закрытие нескольких потоков правильно

Я добавил shutdownHook, который запускает метод, который сообщает серверу о завершении работы. Сервер, в свою очередь, транслирует вызов выключения на все потоки, которые он открыл, что устанавливает логическое значение «isClosed» в каждом потоке равным true.

Что я ожидаю, так это то, что каждый поток, когда доходит до конца метода run() и снова зацикливается, нажимает на условие (! IsClosed) условно, тем самым правильно завершая себя, закрывая все соответствующие сокеты/потоки и возвращение.

Однако, я не знаю, будет ли это правильно закрывать все, так как программа должна завершиться после завершения завершения shutdownhook. Он заканчивается довольно рано, так как все, что он делает, распространяется на закрывающее сообщение. Означает ли это, что некоторые потоки не получат достаточно времени для правильного закрытия?

Если да, то лучшим способом было бы, чтобы shutdownhook вручную закрывал каждую нить, гарантируя, что они закрылись, прежде чем вернуться?

+1

Базовый подход не является неправильным, но вы также можете изучить 'Thread.interrupt()' в случае, если ваши потоки имеют в них блокирующие вызовы. (И имейте в виду, что не все такие вызовы прерываются - я считаю, что регулярные чтения сокетов не являются.) – millimoose

+0

, если они являются не-демонами, тогда JVM не выйдет, пока все потоки не вернутся из их метода запуска, независимо от того, метод вернулся. – Affe

+1

Используйте службу-исполнитель, чтобы управлять своими потоками и отключать службу-исполнитель, когда закончите. – assylias

ответ

0

Вы правы, что потоки, вероятно, не будут иметь достаточного времени для правильного завершения, если сервер будет завершен. Однако, в зависимости от того, что вы пытаетесь сделать, это может быть или не быть проблемой. Если нет никакой работы по очистке, то вам, вероятно, не нужно беспокоиться об этом, потому что, если потоки внезапно прекратятся, не вызовет никаких проблем.

Однако, если есть работа по очистке, которая должна быть выполнена (например, запись в базу данных), вам нужно что-то еще. Наилучший способ сделать это (на Java) - это использование Executor/ExecutorService и связанных с ним элементов (http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/Executors.html). Ваша проблема хорошо решена ими, плюс вы получаете некоторые интересные халявы, такие как управление пулами потоков, чтобы масштабирование стало намного проще. Если вы создадите новый поток для каждого клиента, у вас появятся большие проблемы при попытке масштабирования позже, потому что вы не можете создавать миллионы потоков в минуту, например.

Использование материалов Excecutor - это немного корректировка, если вы привыкли использовать необработанные потоки, но это стоит исследования. Удачи!

+0

Если я понимаю это право, я просто создаю ExecutorService с использованием фабрики Executors. Затем я добавляю свои потоки с выполнением, и служба управляет им для меня? Затем, чтобы закрыть, я использую комбинацию выключения и shutdownNow для очистки потоков при закрытии приложения? – ImpGuard

+0

Да, вы правы. При построении ваших потоков вы захотите правильно обработать InterruptedException таким образом, что если он будет добавлен в ваш поток, будет проведена правильная очистка. Нитки, которые не переоценивают свое условие завершения после того, как поймают InterrupedException, не могут законно прекратить использование ExecutorService. Вы можете легко проверить их статус, используя ExecutorService.isTerminated() или waitTermination() в своем основном потоке, если хотите убедиться, что окончание произошло изящно, прежде чем выйти из приложения. Надеюсь, это поможет! –

0

Использование ExecutorService - это современный способ сделать это. Он берет так много отрядных битов от кода.

Here - хорошее место для начала.

+0

Большое спасибо. ExecutorService действительно кажется правильным способом реализации этого. – ImpGuard

0

Выключение shutdownHook происходит слишком поздно, чтобы цикл был полезен таким образом. Ожидается, что он будет завершен быстро, и JVM уже на пути вниз, который может принимать существующие потоки с ним, если они являются демонами.

Я бы просто установил таймаут чтения на потоках соединения, например, 15-30 секунд. Если тайм-аут происходит (SocketTimeoutException), закройте сокет и выйдите из потока. Конечно, клиентам придется справляться с упавшими соединениями, но они должны это сделать уже. Затем, когда вы хотите завершить работу, просто прекратите принимать новые соединения (например, закройте ServerSocket и правильно обработайте поток потоков с полученным исключением). Когда все существующие потоки соединений выйдут, JVM выйдет, и на самом деле это займет не больше времени ожидания и длины самой длинной транзакции. Убедитесь, что потоки соединений не являются демонами.

Если вы не возражаете клиентов получать сколы в середине сделке, просто позвоните System.exit().

0

Рассматривали ли вы сделать ваши темы демоной тему. просто добавьте t.setdaemon (true); перед вызовом метода начала потока. Если эти потоки должны быть закончены, когда программа завершена, чем их демон, они убьют их, как только закончится весь другой поток не-демона. потоки, которые используются в threadpool, являются хорошим примером для потоков, которые должны быть демонами. , и я действительно думаю, что это может быть полезно для вас.

Смежные вопросы