Java: тайм-аут набора на определенном блоке кода?

Действительно ли возможно вынудить Java выдать Исключение после того, как некоторый блок кода будет работать дольше, чем приемлемый?

62
задан 19 April 2011 в 14:52

4 ответа

Я создал очень простое решение, не используя платформ или API. Это выглядит более изящным и понятным. Класс называют TimeoutBlock.

public class TimeoutBlock {

 private final long timeoutMilliSeconds;
    private long timeoutInteval=100;

    public TimeoutBlock(long timeoutMilliSeconds){
        this.timeoutMilliSeconds=timeoutMilliSeconds;
    }

    public void addBlock(Runnable runnable) throws Throwable{
        long collectIntervals=0;
        Thread timeoutWorker=new Thread(runnable);
        timeoutWorker.start();
        do{ 
            if(collectIntervals>=this.timeoutMilliSeconds){
                timeoutWorker.stop();
                throw new Exception("<<<<<<<<<<****>>>>>>>>>>> Timeout Block Execution Time Exceeded In "+timeoutMilliSeconds+" Milli Seconds. Thread Block Terminated.");
            }
            collectIntervals+=timeoutInteval;           
            Thread.sleep(timeoutInteval);

        }while(timeoutWorker.isAlive());
        System.out.println("<<<<<<<<<<####>>>>>>>>>>> Timeout Block Executed Within "+collectIntervals+" Milli Seconds.");
    }

    /**
     * @return the timeoutInteval
     */
    public long getTimeoutInteval() {
        return timeoutInteval;
    }

    /**
     * @param timeoutInteval the timeoutInteval to set
     */
    public void setTimeoutInteval(long timeoutInteval) {
        this.timeoutInteval = timeoutInteval;
    }
}

пример:

try {
        TimeoutBlock timeoutBlock = new TimeoutBlock(10 * 60 * 1000);//set timeout in milliseconds
        Runnable block=new Runnable() {

            @Override
            public void run() {
                //TO DO write block of code to execute
            }
        };

        timeoutBlock.addBlock(block);// execute the runnable block 

    } catch (Throwable e) {
        //catch the exception here . Which is block didn't execute within the time limit
    }

Это было так полезно для меня, когда я должен был соединиться с учетной записью FTP. Затем загрузите и загрузите материал. иногда соединение FTP зависает или полностью повреждается. Это заставило целую систему понижаться. и мне был нужен способ обнаружить его и предотвратить его. Таким образом, я создал это и использовал его. Работы вполне прилично.

2
ответ дан 31 October 2019 в 13:59

Я столкнулся с подобным видом проблемы, где моя задача состояла в том, чтобы продвинуть сообщение к SQS в особом тайм-ауте. Я использовал тривиальную логику выполнения его через другой поток и ожидающий на его будущем объекте путем определения тайм-аута. Это дало бы мне исключение ТАЙМ-АУТА в случае тайм-аутов.

final Future<ISendMessageResult> future = 
timeoutHelperThreadPool.getExecutor().submit(() -> {
  return getQueueStore().sendMessage(request).get();
});
try {
  sendMessageResult = future.get(200, TimeUnit.MILLISECONDS);
  logger.info("SQS_PUSH_SUCCESSFUL");
  return true;

} catch (final TimeoutException e) {
  logger.error("SQS_PUSH_TIMEOUT_EXCEPTION");
}

, Но существуют случаи, где Вы не можете остановить код, выполняемый другим потоком, и Вы получаете истинные отрицательные стороны в этом случае.

, Например - В моем случае, мой запрос достигнутый SQS и в то время как сообщение продвигалось, моя логика кода, встретился с указанным тайм-аутом. Теперь в действительности мое сообщение было продвинуто в Очередь, но мой основной поток предположил, что это было отказавшим из-за исключения ТАЙМ-АУТА. Это - тип проблемы, которой можно избежать вместо того, чтобы быть решенным. Как в моем случае я избежал его путем обеспечения тайм-аута, который будет достаточен почти во всех случаях.

, Если код Вы хотите прервать, в Вас приложение и не что-то как вызов API затем, можно просто использовать

future.cancel(true)

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

"Попытки отменить выполнение этой задачи. Эта попытка перестанет работать, если задача уже завершилась, была уже отменена или не могла бы быть отменена по некоторой другой причине. Если успешный, и эта задача не запустился, когда отмену называют, эта задача никогда не должна работать. Если задача уже запустилась, то mayInterruptIfRunning параметр определяет, должен ли поток, выполняющий эту задачу, быть прерван, inan пытаются остановить задачу".

0
ответ дан 31 October 2019 в 13:59

Если Вы хотите CompletableFuture путем, у Вас мог бы быть метод как

public MyResponseObject retrieveDataFromEndpoint() {

   CompletableFuture<MyResponseObject> endpointCall 
       = CompletableFuture.supplyAsync(() ->
             yourRestService.callEnpoint(withArg1, withArg2));

   try {
       return endpointCall.get(10, TimeUnit.MINUTES);
   } catch (TimeoutException 
               | InterruptedException 
               | ExecutionException e) {
       throw new RuntimeException("Unable to fetch data", e);
   }
}

при использовании пружины Вы могли бы аннотировать метод @Retryable так, чтобы он повторил метод три раза, если исключение выдается.

1
ответ дан 31 October 2019 в 13:59

Вместо того, чтобы иметь задачу в новом потоке и таймер в основном потоке, имейте таймер в новом потоке и задачу в основном потоке:

public static class TimeOut implements Runnable{
    public void run() {
        Thread.sleep(10000);
        if(taskComplete ==false) {
            System.out.println("Timed Out");
            return;
        }
        else {
            return;
        }
    }
}
public static boolean taskComplete = false;
public static void main(String[] args) {
    TimeOut timeOut = new TimeOut();
    Thread timeOutThread = new Thread(timeOut);
    timeOutThread.start();
    //task starts here
    //task completed
    taskComplete =true;
    while(true) {//do all other stuff }
}
0
ответ дан 31 October 2019 в 13:59

Другие вопросы по тегам:

Похожие вопросы: