#java #spring #spring-boot
#java #многопоточность #параллелизм
Вопрос:
У меня есть метод, который записывает данные в базу данных. Требование состоит в том, чтобы убедиться, что этот метод не выполняется по истечении определенного времени. Если он вернется до этого, то ничего не следует предпринимать.
Единственный базовый подход, который я могу придумать, — это сделать что-то подобное.
public class LimitedRuntime {
public static void writeToDb(){
// writes to the database
}
public static void main(String[] args) {
long totalExecutionTime = 8000L;
long startTime = System.currentTimeMillis();
while(System.currentTimeMillis() - startTime < totalExecutionTime )
{
writeToDb();
}
}
}
Одна из проблем этого подхода заключается в том, что даже если метод возвращается раньше максимального общего времени выполнения, даже тогда программа останавливается, чтобы дождаться истечения этого времени.
Как я могу сделать это лучше (или, может быть, более правильно)? И если мы используем Thread
, как мы можем узнать , какой Thread
из них выполняет этот метод?
Комментарии:
1. Как насчет самого незаметного решения,
Δt = t2 - t2
о.О
Ответ №1:
Вы можете сделать это, отправив свою работу исполнителю:
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(4);
Future<?> future = executor.submit(new Runnable() {
@Override
public void run() {
writeToDb(); // <-- your job
}
});
executor.shutdown(); // <-- reject all further submissions
try {
future.get(8, TimeUnit.SECONDS); // <-- wait 8 seconds to finish
} catch (InterruptedException e) { // <-- possible error cases
System.out.println("job was interrupted");
} catch (ExecutionException e) {
System.out.println("caught exception: " e.getCause());
} catch (TimeoutException e) {
future.cancel(true); // <-- interrupt the job
System.out.println("timeout");
}
// wait all unfinished tasks for 2 sec
if(!executor.awaitTermination(2, TimeUnit.SECONDS)){
// force them to quit by interrupting
executor.shutdownNow();
}
}
Комментарии:
1. Прерывая поток, вы должны помнить, что вы должны добавить условие like
if (isInterrupted()) { return; }
. Без этого Поток вообще не будет прерван! Не знаю, как это будет работать с запускаемым интерфейсом…2. Да, я предположил, что драйвер БД должен поддерживать это.
3. Я с этим не знаком
ExecutorService
. Я буду читать об этом. Кстати, не могли бы вы просто сказать мне а) Что произойдет выше, если метод завершится и вернется до истечения максимального времени? б) я хочу завершить работу метода мгновенно, как только истечет установленный срок. Для этого я должен использоватьexecutor.awaitTermination(0, TimeUnit.SECONDS)
?4. a) Будущее останавливается в ожидании завершения задания,
main()
поток продолжает выполнение. В этом конкретном случае приложение просто завершит работу. б)future.cancel(true)
следует завершить поток. Поток должен поддерживать завершение, как отметил @bobbel. Ваш драйвер БД должен поддерживать его, если поток выполняет несколько запросов, он должен проверятьThread.interrupted()
флаг между ними.
Ответ №2:
Для этого также существует решение AspectJ с библиотекой jcabi-aspects:
@Timeable(limit = 5, unit = TimeUnit.SECONDS)
public String writeToDb() {
// writeToDb
}
Существует статья, объясняющая это далее: Ограничить время выполнения метода Java