我有一个基本上执行以下操作的Java程序:
public static void main(String[] args)
{
while(true)
{
// does stuff ...
}
}
无限循环是设计的 - 当单独留下时,程序将无限循环。在大多数情况下它工作正常。但是,有时候我想把程序用于维护,当我把它关闭时,我想确保它遍历循环中的所有代码然后退出。
我想知道什么是最好的解决方案。我想到的一个想法是做这样的事情:
public static void main(String[] args)
{
File f = new File("C:\exit.txt");
while(!f.exists())
{
// does stuff ...
}
}
这基本上允许我通过创建一个名为" exit.txt"的文件来优雅地离开循环。这对我的目的来说可能没问题,但我想知道是否有更好的替代方法。
答案 0 :(得分:0)
您可以使用运行时关闭钩子。这样您就不需要使用控制台输入来停止循环。如果正常关闭JVM,则将运行shutdown hook thread。该线程将等待当前循环迭代的结束。请记住,使用挂钩时存在一些限制:https://docs.oracle.com/javase/8/docs/api/java/lang/Runtime.html#addShutdownHook-java.lang.Thread-
import java.util.concurrent.CountDownLatch;
public class Test {
private volatile static CountDownLatch lastIterationLatch = null;
private static boolean stop = false;
public static void main(String [] args) throws Exception {
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
lastIterationLatch = new CountDownLatch(1);
try {
lastIterationLatch.await();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
});
while(!stop) {
System.out.println("iteration start");
Thread.sleep(200);
System.out.println("processing...");
Thread.sleep(200);
System.out.println("processing...");
Thread.sleep(200);
System.out.println("processing...");
Thread.sleep(200);
System.out.println("iteration end");
if(lastIterationLatch != null) {
stop = true;
lastIterationLatch.countDown();
}
}
}
}
答案 1 :(得分:0)
我认为Java 7中引入的WatchService
可能在这里有用(如果您更喜欢基于文件的方法)。来自JavaDocs:
监视已注册对象的更改和事件的监视服务。例如,文件管理器可以使用监视服务来监视目录以进行更改,以便在创建或删除文件时更新其文件列表的显示。
基本上这意味着您可以设置WatchService
来查看文件夹以进行更改。当发生变化时,您可以选择要采取的行动。
以下代码使用WatchService
来监视指定文件夹的更改。发生更改后,它会执行调用者提供的Runnable
(方法runWhenItIsTimeToExit
)。
public class ExitChecker {
private final Path dir;
private final Executor executor;
private final WatchService watcher;
// Create the checker using the provided path but with some defaults for
// executor and watch service
public ExitChecker(final Path dir) throws IOException {
this(dir, FileSystems.getDefault().newWatchService(), Executors.newFixedThreadPool(1));
}
// Create the checker using the provided path, watcher and executor
public ExitChecker(final Path dir, final WatchService watcher, final Executor executor) {
this.dir = dir;
this.watcher = watcher;
this.executor = executor;
}
// Wait for the folder to be modified, then invoke the provided runnable
public void runWhenItIsTimeToExit(final Runnable action) throws IOException {
// Listen on events in the provided folder
dir.register(watcher,
StandardWatchEventKinds.ENTRY_CREATE,
StandardWatchEventKinds.ENTRY_DELETE,
StandardWatchEventKinds.ENTRY_MODIFY);
// Run it async, otherwise the caller thread will be blocked
CompletableFuture.runAsync(() -> {
try {
watcher.take();
} catch (InterruptedException e) {
// Ok, we got interrupted
}
}, executor).thenRunAsync(action);
}
}
那么,我们如何使用检查器呢?嗯,以下代码说明了这一点:
public static void main(String... args) throws IOException, InterruptedException {
// Setup dirs in the home folder
final Path directory = Files.createDirectories(
new File(System.getProperty("user.home") + "/.exittst").toPath());
// In this case we use an AtomicBoolean to hold the "exit-status"
AtomicBoolean shouldExit = new AtomicBoolean(false);
// Start the exit checker, provide a Runnable that will be executed
// when it is time to exit the program
new ExitChecker(directory).runWhenItIsTimeToExit(() -> {
// This is where your exit code will end up. In this case we
// simply change the value of the AtomicBoolean
shouldExit.set(true);
});
// Start processing
while (!shouldExit.get()) {
System.out.println("Do something in loop");
Thread.sleep(1000);
}
System.out.println("Exiting");
}
最后,你如何退出该计划呢?只需触摸指定文件夹中的文件即可。例如:
cd ~/.exittst
touch exit-now.please
资源:
WatchService
为slow on Mac OS X 答案 2 :(得分:-1)
对于快速/脏的内容,请使用信号:
boolean done = false;
// ...
Signal.handle(new Signal("USR1"), new SignalHandler() {
@Override
public void handle(Signal signal) {
// signal triggered ...
done = true;
}
});
// ...
while(!done) { ... }
然后,使用kill -USR1 _pid_
触发信号。
答案 3 :(得分:-1)
您可以在下面的测试程序中使用AtomicBoolean。 要暂停,只需在控制台中输入true即可恢复类型false。该计划永远不会退出。
public class Test2 {
public static void main(String[] args) {
final AtomicBoolean suspended = new AtomicBoolean(false);
new Thread() {
public void run() {
while (true)
{
Scanner sc = new Scanner(System.in);
boolean b = sc.nextBoolean();
suspended.set(b);
}
}
}.start();
while(true){
if(!suspended.get()){
System.out.println("working");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
else{
//System.exit(0) //if you want to exit rather than suspend uncomment.
}
}
}
}