Простой тайм-аут в Java

Кто-нибудь может подсказать мне, как я могу использовать простой тайм-аут в Java? В основном в моем проекте я выполняю заявление br.readLine(), который читает ответ от модема. Но иногда модем не отвечает. Для этого я хочу добавить тайм-аут. Я ищу код вроде:

try {
    String s= br.readLine();
} catch(TimeoutException e) {
    System.out.println("Time out has occurred");
}

5 ответов

То, что вы ищете, можно найти здесь. Может существовать более элегантный способ сделать это, но один из возможных подходов

Вариант 1 (предпочтительный):

final Duration timeout = Duration.ofSeconds(30);
ExecutorService executor = Executors.newSingleThreadExecutor();

final Future<String> handler = executor.submit(new Callable() {
    @Override
    public String call() throws Exception {
        return requestDataFromModem();
    }
});

try {
    handler.get(timeout.toMillis(), TimeUnit.MILLISECONDS);
} catch (TimeoutException e) {
    handler.cancel(true);
}

executor.shutdownNow();

Вариант 2:

final Duration timeout = Duration.ofSeconds(30);
ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);

final Future<String> handler = executor.submit(new Callable() {
    @Override
    public String call() throws Exception {
        return requestDataFromModem();
    }
});

executor.schedule(new Runnable() {
    @Override
    public void run(){
        handler.cancel(true);
    }      
}, timeout.toMillis(), TimeUnit.MILLISECONDS);

executor.shutdownNow();

Это всего лишь черновик, так что вы можете получить основную идею.

В настоящее время вы можете использовать

      try {
    String s = CompletableFuture.supplyAsync(() -> br.readLine())
                                .get(1, TimeUnit.SECONDS);
} catch (TimeoutException e) {
    System.out.println("Time out has occurred");
} catch (InterruptedException | ExecutionException e) {
    // Handle
}

РЕДАКТИРОВАТЬ: poseidon правильно указывает, что в случае тайм-аута вышеуказанный подход не прерывает основной поток, который обрабатывает задачу Future. Без прерывания базовый поток будет продолжать обрабатывать задачу Future до завершения, не зная, что результат больше не нужен. С прерыванием базовый поток может, по крайней мере, увидеть (если он проверит), что он был прерван, что позволит ему изящно завершить обработку и выйти.

Для методов в JDK, которые блокируют ввод-вывод, по соглашению они реализованы таким образом, что они проверяют состояние прерывания вызывающего потока (и выдают InterruptedException, если оно истинно). Таким образом, прерывание потока может позволить ему быстро выйти даже из потенциально бесконечных ситуаций ожидания, таких как чтение из источника ввода.



Без дальнейшего изложения, если мы хотим прервать базовый поток по тайм-ауту, мы можем настроить:

      Future<String> future = CompletableFuture.supplyAsync(() -> br.readLine());
try {
    String s = future.get(1, TimeUnit.SECONDS);
} catch (TimeoutException e) {
    System.out.println("Time out has occurred");
    
    future.cancel(true);
} catch (InterruptedException | ExecutionException e) {
    // Handle
}
          @Singleton
    @AccessTimeout(value=120000)
    public class StatusSingletonBean {
      private String status;
    
      @Lock(LockType.WRITE)
      public void setStatus(String new Status) {
        status = newStatus;
      }
      @Lock(LockType.WRITE)
      @AccessTimeout(value=360000)
      public void doTediousOperation {
        //...
      }
    }
    //The following singleton has a default access timeout value of 60 seconds, specified //using the TimeUnit.SECONDS constant:
    @Singleton
    @AccessTimeout(value=60, timeUnit=SECONDS) 
    public class StatusSingletonBean { 
    //... 
    }  
    //The Java EE 6 Tutorial

//https://docs.oracle.com/javaee/6/tutorial/doc/gipvi.html

Пример 1 не будет компилироваться. Эта версия компилируется и запускается. Он использует лямбда-функции, чтобы сократить его.

/*
 * [RollYourOwnTimeouts.java]
 *
 * Summary: How to roll your own timeouts.
 *
 * Copyright: (c) 2016 Roedy Green, Canadian Mind Products, http://mindprod.com
 *
 * Licence: This software may be copied and used freely for any purpose but military.
 *          http://mindprod.com/contact/nonmil.html
 *
 * Requires: JDK 1.8+
 *
 * Created with: JetBrains IntelliJ IDEA IDE http://www.jetbrains.com/idea/
 *
 * Version History:
 *  1.0 2016-06-28 initial version
 */
package com.mindprod.example;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import static java.lang.System.*;

/**
 * How to roll your own timeouts.
 * Based on code at http://stackru.com/questions/19456313/simple-timeout-in-java
 *
 * @author Roedy Green, Canadian Mind Products
 * @version 1.0 2016-06-28 initial version
 * @since 2016-06-28
 */

public class RollYourOwnTimeout
    {

    private static final long MILLIS_TO_WAIT = 10 * 1000L;

    public static void main( final String[] args )
        {
        final ExecutorService executor = Executors.newSingleThreadExecutor();

        // schedule the work
        final Future<String> future = executor.submit( RollYourOwnTimeout::requestDataFromWebsite );

        try
            {
            // where we wait for task to complete
            final String result = future.get( MILLIS_TO_WAIT, TimeUnit.MILLISECONDS );
            out.println( "result: " + result );
            }

        catch ( TimeoutException e )
            {
            err.println( "task timed out" );
            future.cancel( true /* mayInterruptIfRunning */ );
            }

        catch ( InterruptedException e )
            {
            err.println( "task interrupted" );
            }

        catch ( ExecutionException e )
            {
            err.println( "task aborted" );
            }

        executor.shutdownNow();

        }
/**
 * dummy method to read some data from a website
 */
private static String requestDataFromWebsite()
    {
    try
        {
        // force timeout to expire
        Thread.sleep( 14_000L );
        }
    catch ( InterruptedException e )
        {
        }
    return "dummy";
    }

}

Используйте эту строку кода:

Thread.sleep(1000);

Это будет спать в течение 1 секунды.

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