【问题标题】:How to run a program forever in Java? Is System.in.read() the only way?如何在 Java 中永远运行一个程序? System.in.read() 是唯一的方法吗?
【发布时间】:2021-12-25 18:57:51
【问题描述】:

我拍了this code

 28     public static void main(String[] args) throws IOException {
 29         HttpServer httpServer = startServer();
 30         System.out.println(String.format("Jersey app started with WADL available at "
 31                 + "%sapplication.wadl\nTry out %shelloworld\nHit enter to stop it...",
 32                 BASE_URI, BASE_URI));
 33         System.in.read();
 34         httpServer.stop();
 35     } 

第 33 行“System.in.read()”是否意味着它将阻塞直到有输入?这在使用 UNIX rc 脚本启动 Java 应用程序时是否也有效 - 不是从命令行手动启动?

我想编写一个 Java 应用程序来监听 HTTP 连接。该应用程序将在系统启动时自动启动(使用 UNIX rc 脚本)。这意味着应用程序将持续运行——理论上永远运行,直到故意停止。在 Java main() 方法中实现这一点的最佳方法是什么?

【问题讨论】:

  • 不要停止httpService ?

标签: java


【解决方案1】:

它看起来像一个奇怪的黑魔法,但遵循非常优雅的方式

Thread.currentThread().join();

因此,当前线程(例如 main)在 join() 上等待线程 main(即其自身)结束。死锁。

被阻塞的线程当然不能是守护线程。

【讨论】:

  • 这很完美。不知道有没有其他问题
【解决方案2】:

在 Java 中保留 main 方法不会自动结束程序。

如果没有更多的非守护线程在运行,则 JVM 存在。默认情况下,唯一的非守护线程是主线程,当您离开 main 方法时它会结束,因此会停止 JVM。

所以要么不要结束主线程(不让main方法返回)或者创建一个永不返回的新非守护线程(在至少在您想要结束 JVM 之前)。

由于该规则实际上非常合理,因此通常是此类线程的完美候选者。例如,对于 HTTP 服务器,它可能是实际接受连接并将它们交给其他线程进行进一步处理的线程。只要该代码在运行,JVM 就会继续运行,即使 main 方法早已结束运行。

【讨论】:

  • 恕我直言,您没有完全回答这个问题。你不是说如何阻止非守护线程。正如我在下面发布的stackoverflow.com/a/33502519/3114959 非常优雅的方法是调用Thread.currentThread().join();
  • 故意阻塞主线程而没有任何实际工作要做是错误的方法。最好将实际工作的线程标记为非守护线程。如果你没有这样的线程,那么问题是为什么你需要一个正在运行的 JVM ;-)
【解决方案3】:

@Joachim 的回答是正确的。

但如果(出于某种原因)您仍想无限期地阻塞 main 方法(不进行轮询),那么您可以这样做:

public static void main(String[] args) {
    // Set up ...
    try {
        Object lock = new Object();
        synchronized (lock) {
            while (true) {
                lock.wait();
            }
        }
    } catch (InterruptedException ex) {
    }
    // Do something after we were interrupted ...
}

由于锁对象只对这个方法可见,所以notify它不能,所以wait()调用不会返回。但是,其他一些线程仍然可以通过中断 main 线程来解除阻塞。

【讨论】:

  • 理论上wait 可能会被虚假唤醒(没有相应的notify() 调用)。这就是为什么你永远不应该在循环之外调用它。
【解决方案4】:

while (true) { ... } 应该会持续很长时间。当然,你最终必须想办法阻止它。

一个常见的技巧是拥有一些volatile boolean running = true,然后将主循环设置为while (running) { ... },并定义线程设置running = false的一些标准。

【讨论】:

  • 我考虑过使用“while(true);”循环也是如此,但是运行它的线程是否会连续评估表达式,从而消耗不必要的 CPU 周期?
  • 嗯,这取决于它在做什么。如果它花费大部分时间等待来自 HTTP 连接的数据,那么它就不会消耗不必要的 CPU 周期。我应该澄清一下,我不是在建议一个空循环(称为忙等待),而是一个主事件循环。
【解决方案5】:

回到线程,这正是我想要的。顺便说一句,这个很棒的tutorial 帮了我很多。

Main.java

public class Main {
    public static void main(String args[]) {
        ChatServer server = null;
        /*if (args.length != 1)
            System.out.println("Usage: java ChatServer port");
        else*/
            server = new ChatServer(Integer.parseInt("8084"));
    }
}

ChatServer.java 类扩展了一个 Runnable

public class ChatServer implements Runnable
{  private ChatServerThread clients[] = new ChatServerThread[50];
    private ServerSocket server = null;
    private Thread       thread = null;
    private int clientCount = 0;

    public ChatServer(int port)
    {  try
    {  System.out.println("Binding to port " + port + ", please wait  ...");
        server = new ServerSocket(port);
        System.out.println("Server started: " + server);
        start(); }
    catch(IOException ioe)
    {
        System.out.println("Can not bind to port " + port + ": " + ioe.getMessage()); }
    }

    public void start() {  
        if (thread == null) {  
            thread = new Thread(this);
            thread.start();
        }
    }
.... pleas continue with the tutorial

因此,在 main 方法中,正在实例化一个 Runnable 和一个新线程,如
public void start() { 正在使用 runnable 实例化。 这种情况下 JVM 会继续执行该进程,直到您退出项目或调试器。

顺便说一句,这与 Joachim Sauer 在他的回答中发布的相同。

【讨论】:

    【解决方案6】:

    Java 程序在没有非守护线程运行时终止。您所需要的只是拥有一个这样的运行线程。您可以使用无限循环来做到这一点,但这会消耗 CPU 周期。以下似乎是一种合理的方法。

    ExecutorService executor = Executors.newSingleThreadExecutor();
    executor.submit(() -> {}); //submit a task that does what you want (in this case, nothing)
    

    【讨论】:

      【解决方案7】:

      我们也可以通过 ReentrantLock 实现相同的效果并在其上调用 wait():

      public class Test{
      private static Lock mainThreadLock = new ReentrantLock();
      
      public static void main(String[] args) throws InterruptedException {
      
      System.out.println("Stop me if you can");
      synchronized (mainThreadLock) {
          mainThreadLock.wait();
       }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-10-03
        • 2013-09-17
        • 2013-05-03
        相关资源
        最近更新 更多