0

Мотивация по этому вопросу Я запускаю огромный продукт, который работает на очень дорогом оборудовании. Выключение его для целей тестирования невозможно, а также не создает плохую банку в производственной среде. Мне нужно быть как можно увереннее до почти, чтобы я не испортил производственную среду.ScheduledExecutorService использование и очистка заблокированного гнезда instream

Мне нужно, чтобы приведенный ниже код был рассмотрен по очевидным проблемам, прежде чем запускать его на этапе настройки (что так дорого).

Задача У меня есть приложение на основе сокетов, иногда клиенты не отправляют запрос CloseConnection явно. И иногда IOException не возникает, там, удерживая потоки при блокировании вызова readObject.

Мне нужно закрыть эту тему, закрыв соединение после таймаута. Если я получаю новый запрос с сервера, время ожидания обновляется.

Таким образом, вы будете видеть 3 части ниже

  • инициализирующий
  • readObject вызов в то время как (истинный) цикл, и запланированное обслуживание сброса
  • фактическое закрытие Instream

Код

У меня есть ru рекомендуется использовать ScheduledExecutorService вместо Timer/TimerTask.

class StreamManager { 
    .... 
    private ScheduledExecutorService activityTimeOut = Executors 
      .newSingleThreadScheduledExecutor(); 
    private CloseConnectionOnTimeOut closeOnTimeOut = new CloseConnectionOnTimeOut(); 
    .... 

    public void initialize(Socket newClientSocket, ObjectInputStream newInputStream, 
      ObjectOutputStream newOutputStream, ThreadMonitor newThreadMonitor) { 
     .... 
     closeOnTimeOut.setInputStream(myInputStream); 
     activityTimeOut.scheduleAtFixedRate(closeOnTimeOut, 0, Globals.INACTIVITY_TIME_OUT, 
       TimeUnit.MILLISECONDS); 
    } 

    public void run() { 
    .... 
    while (true) { 
      try { 
       AMessageStrategy incomingCommand = (AMessageStrategy) myInputStream 
         .readObject(); 
       activityTimeOut.shutdown(); 
       activityTimeOut.scheduleAtFixedRate(closeOnTimeOut, 0, 
         Globals.INACTIVITY_TIME_OUT, TimeUnit.MILLISECONDS); 
     .... 
    } 
    .... 
} 
class CloseConnectionOnTimeOut implements Runnable { 
     private ObjectInputStream myInputStream; 

     public CloseConnectionOnTimeOut() { 

     } 

     public void setInputStream(ObjectInputStream myInputStream) { 
      this.myInputStream = myInputStream; 
     } 

     public void run() { 
      try { 
       myInputStream.close(); 
       myOutputStream.close(); 
       clientSocket.close(); 
       log.info("Time out occured for client, closed connection forcefully.") ; 
      } catch (IOException e) { 
       e.printStackTrace(); 
       log.fatal("Time out has occured, yet unable to clean up client connection. Keep a watch out on \"Size of clientStreamQ\""); 
      } 
     } 
    } 

Edit: Просто протестировали меньшее применение, и это, кажется, работает. Мне все еще нужна ваша обратная связь.

Редактировать снова:

Я изменил код ниже в соответствии с уведомлением.

Инициализация

private ScheduledExecutorService activityTimeOut = Executors 
      .newSingleThreadScheduledExecutor(); 
    private Future<Void> timeoutTask ; 
    private CloseConnectionOnTimeOut closeOnTimeOut = new CloseConnectionOnTimeOut(); 

Удалены этот код

closeOnTimeOut.setInputStream(myInputStream); 
activityTimeOut.scheduleAtFixedRate(closeOnTimeOut, 0, Globals.INACTIVITY_TIME_OUT, 
       TimeUnit.MILLISECONDS); 

Заменено до и после readObject

timeoutTask = (Future<Void>) activityTimeOut.scheduleAtFixedRate(
         closeOnTimeOut.setInputStream(myInputStream), 0, 
         Globals.INACTIVITY_TIME_OUT, TimeUnit.MILLISECONDS); 
AMessageStrategy incomingCommand = (AMessageStrategy) myInputStream 
         .readObject(); 
timeoutTask.cancel(true) ; 

На Cleanup

activityTimeOut.shutdown() ; 

ответ

1

Вы не можете отправить задания на ExecutorService уже была закрыта. Если вы хотите остановить выполнение задачи, cancel это. Кроме того, ваша задача отмены будет запланирована для запуска, как только инициализируется StreamManager - если есть пробел между инициализацией и запуском, вы можете столкнуться с проблемами.Я хотел бы предложить, чтобы создать и запланировать новую задачу перед попыткой чтения из сокета, и отменить его после чтения удалось:

while (true) { 
    ... 
    Future<Void> timeoutTask = activityTimeOut.schedule(new CloseConnection(/*init with streams*/), Globals.INACTIVITY_TIME_OUT, TimeUnit.MILLISECONDS); 
    try { 
     AMessageStrategy incomingCommand = (AMessageStrategy) myInputStream.readObject(); 
    } finally { 
     timeoutTask.cancel(false); 
    } 
    ... 
} 

В ВЫМЫТЬ способе StreamManager или в конце run() вы должны выключение б/у ScheduledExecutorService.

Если ваше программное обеспечение является критически важным, я бы тщательно его протестировал локально. Записывайте единичные тесты и, возможно, небольшие интеграционные тесты, чтобы проверить, работает ли отмена. Но я боюсь, что это решение довольно хрупкое. Многопоточность и ввод-вывод добавляют много неопределенностей.

+0

спасибо. Я добавил измененный код, пожалуйста, проверьте еще раз. И да, мне нужно будет протестировать его на этапе, прежде чем я его выпущу. Одно изменение, однако, я создал объект CloseConneciton раньше, чтобы избежать накопления памяти, является ли это хорошей задачей? – Siddharth