Прервать поток, выполняющий HTTP-вызов в Java

Я пишу java-программу для HTTP-вызова сервера в другом потоке. Следующий код я выполняю в отдельной вызываемой задаче в исполнителе пула потоков.

public static class MyRunnable implements Callable<Boolean>{

    @Override
    public Boolean call() {
        HttpURLConnection conn = null;
        try {
            URL url = new URL("http://www.myserver.com");
            conn = (HttpURLConnection) url.openConnection();
            conn.setConnectTimeout(5000);
            conn.setReadTimeout(5000);
            conn.setRequestMethod("GET");
            int response = conn.getResponseCode();
                            return response == 200;
        }
        catch (IOException e) {
            e.printStackTrace();
                            return false;
        } catch (Exception e) {
            e.printStackTrace();
                            return false;
        }
    }
}

По какой-то причине сервер не отвечает или сервер отвечает очень медленно. Из-за поведения этого сервера ни тайм-аут соединения, ни таймауты чтения никогда не происходят.

Следовательно, я хочу отслеживать эту задачу (выполняющуюся в исполнителе пула потоков) и через некоторое время прервать поток и убедиться, что я удалю эту задачу из пула, чтобы пул потоков не содержал эту задачу и освободил все ресурсы, занятые этим нить.

Я пробовал Future java, как показано ниже

 ThreadPoolExecutor tpe = new ThreadPoolExecutor(2, 5, 5, TimeUnit.SECONDS, new      ArrayBlockingQueue<Runnable>(10));
 Future<Boolean> f = tpe.submit(new MyRunnable());
  try {
        Boolean success = f.get(5000, TimeUnit.MILLISECONDS);
    } catch (Exception e) {
        e.printStackTrace();
    }

С помощью этого кода я получаю TimeoutException от вызова f.get через 5000 миллисекунд, если поток, который обрабатывает MyRunnable задачу, не отвечает. Но я вижу, что задача будет продолжать выполняться в исполнителе пула потоков, если он застрял на HttpURLConnection.getResponseCode().

Когда я попробовал f.cancel(true), он не прерывает поток, когда задача застревает на HttpURLConnection.getResponseCode() вызове метода. Я понимаю, что поток будет прерван только тогда, когда он проверит его при следующей возможности. Следовательно, я полагаю, что future.cancel в этом случае не поможет.

Итак, как мне выйти из этого вызова (взаимодействуя с исполнителем пула потоков) и убедиться, что задача удалена из пула и соответствующий поток свободен для обработки различных задач?

Заранее благодарим за ответ.

Спасибо,

Раагу


person Raghavendra Nilekani    schedule 22.04.2014    source источник
comment
Во-первых, используйте Executors.newXXX, а не конструктор. Во-вторых, ваш вопрос неясен - у вас установлен тайм-аут в 5 секунд (используйте TimeUnit.SECONDS.toMillis(5) вместо 5000), поэтому соединение прервется через 5 секунд. Что вы имеете в виду под задачей будет продолжать работать в пуле потоков?   -  person Boris the Spider    schedule 22.04.2014
comment
Борис, даже 5000 миллисекунд (что составляет 5 секунд) истекает через 5 секунд. Нет проблем с этим. И после истечения времени ожидания future.get () поток, который обрабатывает вызываемую задачу в пуле, продолжит выполнение этой задачи. Я хочу, чтобы этот поток покинул эту вызываемую задачу и вернулся в пул. Executors.newXXX не помогает. Я не могу освободить поток, если он застрял при вызове http.   -  person Raghavendra Nilekani    schedule 22.04.2014
comment
Я просто скопировал и вставил образец кода вашего MyRunnable, он не компилируется, возврат True / False отсутствует. Также второй образец кода не компилируется, конструктор, принимающий String, отсутствует для runnable.   -  person cheffe    schedule 22.04.2014
comment
cheffe, подборка удалена.   -  person Raghavendra Nilekani    schedule 22.04.2014
comment
К вашему сведению: код работал против моего медленного обслуживания в Джерси, время ожидания которого составляло 5 секунд в conn.getResponseCode (). Вы можете использовать скрипач, чтобы узнать, что происходит на уровне проводов.   -  person Dhana Krishnasamy    schedule 22.04.2014
comment
Dhana, Тайм-аут нормально истекает, когда я подключаюсь к разным серверам. Но, к сожалению, у моего собственного прокси-сервера (не www.myserver.com) не истекло время соединения и не истекло время чтения. Он очень-очень медленно реагирует. Следовательно, я хотел, чтобы вызывающий клиент (поток) был приостановлен через некоторое время.   -  person Raghavendra Nilekani    schedule 23.04.2014


Ответы (2)


Я думаю, вы можете поделиться соединением с другим потоком, который вызовет на нем функцию disconnect () после тайм-аутов. Итак, должно получиться примерно так:

static class ConnectionStopper implements Runnable {

    private final HttpURLConnection conn;

    ConnectionStopper(HttpURLConnection conn) {
        if (conn == null) {
            throw new NullPointerException();
        }
        this.conn = conn;
    }

    @Override
    public void run() {
        conn.disconnect();
    }
}

...

ScheduledExecutorService service = Executors.newScheduledThreadPool(THREAD_POOL_SIZE);
...
// Submit your MyRunnable, then schedule a ConnectionStopper
service.schedule(new ConnectionStopper(conn), 5, TimeUnit.SECONDS);
person Artyom Dmitriev    schedule 22.04.2014
comment
Артём, conn.disconnect тоже не приостанавливает вызов conn.getResponseCode. - person Raghavendra Nilekani; 22.04.2014
comment
Добавляет System.setProperty (http.keepAlive, false); перед открытием справки по подключению? - person Artyom Dmitriev; 22.04.2014

Вызовите Future.cancel ( true) в случае исключения тайм-аута. Это прервет работу, которую вы выполняете в исполняемом файле. Это должно привести к появлению InterruptedIOException ваш вызываемый conn.getResponseCode ().

person Brett Okken    schedule 22.04.2014
comment
Бретт, я пробовал future.cancel (правда). Это не работает. future cancel отправляет потоку сигнал прерывания. Но conn.getResponseCode () этого не выполняет. Следовательно, conn.getResponseCode () продолжает работать. Я ищу что-то, где пул потоков заставляет поток перестать выполнять эту вызываемую задачу, независимо от того, какую работу он выполняет. - person Raghavendra Nilekani; 22.04.2014
comment
Вы в основном зависите от реализации InputStream.read, используемой getResponseCode. Он блокирует ввод-вывод. Однако, задав тайм-аут соединения и тайм-аут чтения, вы не должны ждать дольше суммы этих двух значений. Вообще говоря, статус ответа - это первое, что возвращается из http-запроса. Таким образом, тайм-аут чтения фактически определяет, как долго вы будете ждать после установления соединения. - person Brett Okken; 23.04.2014