在 Java 中阻塞 main 方法总是不好的吗?

Is blocking main method in Java always bad?

我们有一个持续 运行 的应用程序。除了初始化一些后台线程外,main 方法中没有其他内容。后台线程在套接字事件发生时对其进行处理。除了正在处理套接字事件的时间,应用程序仍处于空闲状态。

主要

while (true); // block main thread from exiting. Otherwise, periodic GC calls kills the app.

由于我的应用程序的主要功能是处理事件,因此没有前台任务。阻塞主线程对我来说不好吗?还有哪些替代方案?

由于您的主线程忙于等待,因此需要线程调度程序将其(主线程)放入已调度线程列表中。如果您所在的计算机 运行 您的应用程序的 CPU 少于 4 个,那么您的事件处理线程将受到影响。

有很多其他方法可以在不忙等待的情况下阻塞主线程。上面提到的Thread.join()就是其中之一。如果使用高级并发对象,也可以使用 Future.get()ExecutorService.awaitTermination()

是的,这是一个糟糕的设计。使用 ExecutorService 并向其添加线程。

应避免在 main 方法(或任何其他线程)中阻塞。您 运行 遇到的问题 – 如何创建一些线程并保持 JVM 运行 直到这些线程完成 – 可以用更好的方法解决。

如果您创建一个新的 Thread and call setDaemon(false),那么您将不需要进行任何睡眠或等待操作。通过将线程设置为非守护进程,JVM 将保持 运行 直到该线程完成。来自 Javadoc:

The Java Virtual Machine exits when the only threads running are all daemon threads.

下面是一个示例线程 class,它尝试休眠 2 秒,然后打印出一条消息:

class ExampleThread extends Thread {
    @Override
    public void run() {
        try {
            sleep(2000);
            System.out.println("done sleeping");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

如果你这样称呼它——通过将 daemon 设置为 false——你首先会看到 输出 thread started,然后是 2 秒的空,然后输出 done sleeping.

public static void main(String[] args) {
    ExampleThread t = new ExampleThread();
    t.setDaemon(false);
    t.start();

    System.out.println("thread started");
}

如果您将 t.setDaemon(false) 替换为 t.setDaemon(true) - 这样新线程实际上是一个守护线程 - 然后您将看到输出 thread started,然后 JVM 立即终止。

主线程只是第一个线程,因此与其他线程没有什么不同。如果阻塞了,就意味着浪费了这个线程占用的内存(大约1MB),仅此而已。所以如果这个线程没有工作,我只会从 main 方法中 return 。

我注意到您的代码中有一条注释:阻止主线程退出。否则,周期性的 GC 调用会杀死应用程序。评论是错误的。 GC 调用无法终止应用程序。我怀疑其他线程是以守护进程模式启动的,因此封闭进程不会等待它们完成。

如果您更详细地描述整个过程何时必须结束,我们可以提出更明智的建议。