在 Java 中阻塞 main 方法总是不好的吗?
Is blocking main method in Java always bad?
我们有一个持续 运行 的应用程序。除了初始化一些后台线程外,main 方法中没有其他内容。后台线程在套接字事件发生时对其进行处理。除了正在处理套接字事件的时间,应用程序仍处于空闲状态。
主要
- 启动线程 1 -> while(套接字连接 1 良好) -> 处理事件
- 启动线程 2 -> while(套接字连接 2 良好) -> 处理事件
- 启动线程 3 -> while(套接字连接 3 良好) -> 处理事件
- 启动线程 4 -> while(套接字连接 4 良好) -> 处理事件
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 调用无法终止应用程序。我怀疑其他线程是以守护进程模式启动的,因此封闭进程不会等待它们完成。
如果您更详细地描述整个过程何时必须结束,我们可以提出更明智的建议。
我们有一个持续 运行 的应用程序。除了初始化一些后台线程外,main 方法中没有其他内容。后台线程在套接字事件发生时对其进行处理。除了正在处理套接字事件的时间,应用程序仍处于空闲状态。
主要
- 启动线程 1 -> while(套接字连接 1 良好) -> 处理事件
- 启动线程 2 -> while(套接字连接 2 良好) -> 处理事件
- 启动线程 3 -> while(套接字连接 3 良好) -> 处理事件
- 启动线程 4 -> while(套接字连接 4 良好) -> 处理事件
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 调用无法终止应用程序。我怀疑其他线程是以守护进程模式启动的,因此封闭进程不会等待它们完成。
如果您更详细地描述整个过程何时必须结束,我们可以提出更明智的建议。