Подтвердить что ты не робот

Применение тайм-аута в управлении Java

Я использую стороннюю библиотеку Java для взаимодействия с REST API. API REST иногда может потребовать много времени, чтобы ответить, в результате получилось java.net.ConnectException.

Я хотел бы сократить период ожидания, но не имеет возможности модифицировать стороннюю библиотеку.

Я хотел бы применить некоторую форму управления тайм-аутом вокруг вызова метода Java, чтобы я мог определить, в какой момент отказаться от ожидания.

Это не относится непосредственно к таймаутам сети. Я хотел бы попробовать выполнить операцию и уметь сдаваться после указанного времени ожидания.

Следующее - отнюдь не действительная Java, но концептуально демонстрирует то, что я хотел бы достичь:

try {
    Entity entity = new Entity();
    entity.methodThatMakesUseOfRestApi();
} catch (<it been ages now, I don't want to wait any longer>) {
    throw TimeoutException();
}
4b9b3361

Ответ 1

Я рекомендую TimeLimiter из библиотеки Google Guava.

Ответ 2

Для любых операций не существует общего механизма тайм-аута.

Пока... есть один... с помощью Thread.stop(Throwable). Он работает, и он потокобезопасен, но ваша личная безопасность находится под угрозой, когда сердитая толпа сталкивается с вами.

// realizable 
try
{
    setTimeout(1s);  // 1
    ... any code     // 2 
    cancelTimeout(); // 3
}
catch(TimeoutException te)
{
    // if (3) isn't executed within 1s after (1)
    // we'll get this exception
} 

Ответ 3

Это, вероятно, текущий способ, как это должно быть сделано с простой Java:

public String getResult(final RESTService restService, String url) throws TimeoutException {
    // should be a field, not a local variable
    ExecutorService threadPool = Executors.newCachedThreadPool();

    // Java 8:
    Callable<String> callable = () -> restService.getResult(url);

    // Java 7:
    // Callable<String> callable = new Callable<String>() {
    //     @Override
    //     public String call() throws Exception {
    //         return restService.getResult(url);
    //     }
    // };

    Future<String> future = threadPool.submit(callable);
    try {
        // throws a TimeoutException after 1000 ms
        return future.get(1000, TimeUnit.MILLISECONDS);
    } catch (ExecutionException e) {
        throw new RuntimeException(e.getCause());
    } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
        throw new TimeoutException();
    }
}

Ответ 4

Вы можете использовать Timer и TimerTask.

Ответ 5

Вот класс утилиты, который я написал, который должен делать трюк, если я ничего не пропустил. К сожалению, он может возвращать только общие объекты и бросать общие исключения. Другие могут иметь лучшие идеи о том, как достичь этого.

public abstract class TimeoutOperation {

long timeOut = -1;
String name = "Timeout Operation"; 

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

public long getTimeOut() {
    return timeOut;
}

public void setTimeOut(long timeOut) {
    this.timeOut = timeOut;
}

public TimeoutOperation (String name, long timeout) {
    this.timeOut = timeout;
}

private Throwable throwable;
private Object result;
private long startTime;

public Object run () throws TimeoutException, Exception {
    Thread operationThread = new Thread (getName()) {
        public void run () {
            try {
                result = doOperation();
            } catch (Exception ex) {
                throwable = ex;
            } catch (Throwable uncaught) {
                throwable = uncaught;
            }
            synchronized (TimeoutOperation.this) {
                TimeoutOperation.this.notifyAll();
            }   
        }
        public synchronized void start() {
            super.start();
        }
    };
    operationThread.start();
    startTime = System.currentTimeMillis();
    synchronized (this) {
        while (operationThread.isAlive() && (getTimeOut() == -1 || System.currentTimeMillis() < startTime + getTimeOut())) {
            try {
                wait (1000L);
            } catch (InterruptedException ex) {}
        }   
    }   
    if (throwable != null) {
        if (throwable instanceof Exception) {
            throw (Exception) throwable;
        } else if (throwable instanceof Error) {
            throw (Error) throwable;
        }   
    }   
    if (result != null) {
        return result;
    }   
    if (System.currentTimeMillis() > startTime + getTimeOut()) {
        throw new TimeoutException("Operation '"+getName()+"' timed out after "+getTimeOut()+" ms");
    } else {
        throw new Exception ("No result, no exception, and no timeout!");
    }
}

public abstract Object doOperation () throws Exception;

public static void main (String [] args) throws Throwable {
    Object o = new TimeoutOperation("Test timeout", 4900) {
        public Object doOperation() throws Exception {
            try {
                Thread.sleep (5000L);
            } catch (InterruptedException ex) {}
            return "OK";
        }
    }.run();
    System.out.println(o);
}   

}

Ответ 6

    static final int NUM_TRIES =4;
    int tried =0;
    boolean result =false;
    while (tried < NUM_TRIES && !result)
    {
    try {
        Entity entity = new Entity();

            result = entity.methodThatMakesUseOfRestApi();


    }  
     catch (<it been ages now, I don't want to wait any longer>) {
        if ( tried == NUM_TRIES)
        {
           throw new TimeoutException();
        }

    }
                tried++;
            Thread.sleep(4000);
  }