У меня есть простая Java-программа, которую я использую для генерации элементов и вставки их в БД каждые X секунд в течение определенного времени.
Генерация выполняется с scheduleAtFixedRate
. есть только один из них.
Я хочу, чтобы моя программа полностью закрывалась по окончании запланированной задачи Для этого я использую System.exit()
, когда задача отменяется, но правильный ли это способ?
Вот мой текущий код:
public static void main(String[] args) throws InterruptedException {
c = generateDbConnection(url, user, password);
if (c != null) {
s = generateDbStatement(c);
} else {
System.out.println("ERROR");
return;
}
initialTimestamp = new Date();
TimeUnit.SECONDS.sleep(1);
generateForAnHour();
}
private final static ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
/**
* Generator thread handler Uses Statement from main function
*/
public static void generateForAnHour() {
final Runnable runner = new Runnable() {
public void run() {
String[][] data = new String[numberOfIds][2];
for (int i = 0; i < numberOfIds; i++) {
data[i] = generateDevice();
insertDevice(s, data[i][0], data[i][1]);
}
quantityOfIds += numberOfIds;
}
};
final ScheduledFuture<?> generatorHandle = scheduler.scheduleAtFixedRate(runner, 0, 5, TimeUnit.SECONDS);
scheduler.schedule(new Runnable() {
public void run() {
generatorHandle.cancel(true);
System.out.println("Scheduled ID generator terminated.");
System.exit(0); //TODO Is it really correct way to do it
}
}, timeToRun, TimeUnit.SECONDS);
}
2 ответа
Я не уверен, является ли это правильным способом остановить выполнение вашей программы, если у нее есть еще некоторые функции, но лично я считаю, что это нормально. : D
Итак, как оказалось, ScheduledExecutorService
, по-видимому, создает потоки, не являющиеся демонами, со значением по умолчанию ThreadFactory
, возможно, нам нужно предоставить ему демонический поток.
Однако, если мы вызовем ExecutorService#shutdown
или принудительный ExecutorService#shutdownNow
, он остановит выполнение обеих задач, удалив тем самым потоки, которые не позволяют приложению завершить свою работу:
private final static ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
public static void main(String[] args) {
// Some service code here
generateForAnHour();
}
public static void generateForAnHour() {
// Some code that does work
final Runnable runner = () -> System.out.println("Running...");
final ScheduledFuture<?> generatorHandle = scheduler.scheduleAtFixedRate(runner, 0, 1, TimeUnit.SECONDS);
// Code that interrupts the worker after a specified time
scheduler.schedule(scheduler::shutdown, 5, TimeUnit.SECONDS);
}
Выход:
Running...
Running...
Running...
Running...
Running...
Running...
Process finished with exit code 0
Я надеюсь, это поможет. : D
Этот ответ является второстепенным по отношению к этому, но у него есть другой способ решения проблемы, поэтому я подумал, что он достаточно уместен создать отдельный ответ.
Если вы хотите иметь больше задач в будущем, я считаю, что это решение более масштабируемое и более «правильное».
Он создает потоки демона для runner
и interrupter
. Я думаю, что было бы лучше создать нормальную фабрику потоков для interrupter
, но мне не удалось заставить ее работать, поэтому лучше придерживаться моего первого ответа ...
Здесь generateForAnHour
возвращает Future
, который используется для ожидания необходимого времени.
private final static ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1 , new ThreadFactory() {
@Override
public Thread newThread(final Runnable r) {
Thread t = Executors.defaultThreadFactory().newThread(r);
t.setDaemon(true);
return t;
}
});
public static void main(String[] args) throws InterruptedException, ExecutionException {
// Some service code here
generateForAnHour().get();
}
public static ScheduledFuture<Boolean> generateForAnHour() {
// Some code that does work
final Runnable runner = () -> System.out.println("Running...");
final ScheduledFuture<?> generatorHandle = scheduler.scheduleAtFixedRate(runner, 0, 1, TimeUnit.SECONDS);
// Code that interrupts the worker after a specified time
return scheduler.schedule(() -> generatorHandle.cancel(false), 5, TimeUnit.SECONDS);
}
Если вы не позвоните Future#get
, вы получите только один Running...
в лучшем случае или ни одного вообще.
Если вы решите вернуть runner
будущее, вы, вероятно, получите неприятный CancellationException
вызов get()
:
Exception in thread "main" java.util.concurrent.CancellationException
at java.base/java.util.concurrent.FutureTask.report(FutureTask.java:121)
at java.base/java.util.concurrent.FutureTask.get(FutureTask.java:191)
at com.xobotun.Test.main(Test.java:30)
Я бы использовал подход ExecutorService::shutdown
как более стабильный и понятный. : D
Новые вопросы
java
Java - это язык программирования высокого уровня. Используйте этот тег, если у вас возникли проблемы с использованием или пониманием самого языка. Этот тег редко используется отдельно и чаще всего используется вместе с [spring], [spring-boot], [jakarta-ee], [android], [javafx], [hadoop], [gradle] и [maven].