2015-03-16 6 views
0

Существует поток, который подключается к серверу (HTTP) и ожидает ответа или таймаута ответа (сервер не отвечает, пока он не вернет данные) в цикле. В случае, если ответ вернул обработку потока.Безопасное прерывание потока в Java

При остановке обслуживания необходимо остановить/прервать все потоки, но потоки должны завершить обработку ответа (в случае, если поток обрабатывается, а не только ожидает ответа).

Вот пример кода

public class WaitingResponseThread extends Thread { 

    static final int TIMEOUT = 4 * 1000; 
    static final int PROCESSING_DURATION = 2000; 

    private volatile boolean stopped = false; 
    private volatile boolean processing = false; 

    public void run() { 
     System.out.println("starting child thread"); 
     while(!stopped) { 
      try { 
       // here a thread is awaiting server response (in real life response timeout is 400 sec) 
       // probably it is safe to interrupt the thread now 
       // emulating this with Thread.sleep() 
       System.out.println("awaiting response"); 
       Thread.sleep(TIMEOUT); 

       processing = true; 

       // there is some job on response and we must allow it to finish the job 
       // again emulating delay with Thread.sleep() 
       Thread.sleep(PROCESSING_DURATION); 

       processing = false; 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 
     } 
     System.out.println("ending child thread"); 
    } 

    public void setStopped(boolean stopped) { 
     this.stopped = stopped; 
    } 

    public boolean isProcessing() { 
     return processing; 
    } 

    public static void main(String[] args) { 
     WaitingResponseThread t = new WaitingResponseThread(); 

     // starting thread, it sends a request and waits for a response 
     t.start(); 

     try { 
      Thread.sleep(1); 

      // let's allow the thread to finish normally in case it is processing response 
      t.setStopped(true); 

      System.out.println("awaiting child thread to get response"); 
      Thread.sleep(TIMEOUT + 1); 

      // let's allow the thread to finish processing 
      while(t.isProcessing()) { 
       System.out.println("processing"); 
       Thread.sleep(500); 
      } 

      // we can't wait for 400sec until the next loop check 
      // so as the thread is sleeping we just interrupting it 
      if(t.isAlive()) { 
       System.out.println("killing"); 
       t.interrupt(); 
      } 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     } 
     System.out.println("ending main thread"); 
    } 
} 

Является ли это "прерывание" метод хорошо? Есть ли другой способ не ждать до тех пор, пока время ожидания и не потерять обрабатываемые данные?

+1

Постарайтесь посмотреть http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Future.html#get(long,%20java.util.concurrent.TimeUnit) – DmitryKanunnikoff

+2

альтернативой было бы использовать исполнителей https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Executors.html. Затем вы можете вызвать 'yourPool.shutdown()' и 'yourPool.awaitTermination (time, unit) ', но вам все равно придется обрабатывать прерывания в каждом потоке должным образом, и насколько я знаю, нет никакого чугунного способа гарантировать, что потоки всегда закончат правильно. Вместо того, чтобы изобретать колесо. – Neilos

+0

Метод 'interrupt' не является хорошим выбором, если вы хотите завершить обработку текущих HTTP-запросов. Причина в том, что вызов 'interrupt' может вызвать [' InterruptedIOException'] (http://docs.oracle.com/javase/7/docs/api/java/io/InterruptedIOException.html) операций ввода-вывода в потоке, являющемся прерывание, прекращение попытки ввода-вывода (и HTTP-запросы включают IO) –

ответ

0

Этот

while(t.isProcessing()) { 
    System.out.println("processing"); 
    Thread.sleep(500); 
} 

является формой опроса. Вы должны избегать опроса любой ценой. Если возможно, используйте форму делегирования, когда вызывающий абонент уведомляет вызывающего абонента, когда он выполняется.

Кроме этого, я уверен, что прерывание потока - это то, что вы тоже редко хотите делать, но так, как вы это делаете, хорошо, если вам все равно придется это делать.

+0

Привет, Уорк! Да, я знаю это. Я просто хотел свести к минимуму пример кода. Спасибо! – gumkins

0

Класс Thread имеет несколько функций, которые можно использовать при прерывании.

  • Ловля InterruptionException
  • Используя метод isInterrupted() (not static)
  • Используя метод interrupted() (static)
  • Проверка interrupted() или isInterrupted(), а затем throw new InterruptedException()

С этим вы, вероятно, может сделать вашу нить закончить ток перед тем, как убить его, возможно, в разделе catch.

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