(Java)退出循环“远程”

时间:2015-01-01 21:44:24

标签: java infinite-loop

我有一个基本上执行以下操作的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"的文件来优雅地离开循环。这对我的目的来说可能没问题,但我想知道是否有更好的替代方法。

4 个答案:

答案 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

资源:

答案 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.
        }
    }

}

}