南宁网站忧化网站开发使用的技术有哪些
2026/1/24 12:01:10 网站建设 项目流程
南宁网站忧化,网站开发使用的技术有哪些,建站之星模板好吗,WordPress安装jetpack文章目录Java面试必看#xff1a;如何让Main线程成为最后一个退出的秘密#xff01;一、问题背景#xff1a;为什么我们要关心Main线程的退出顺序#xff1f;二、常见的误区#xff1a;为什么直接运行代码会导致Main线程提前退出#xff1f;示例代码#xff1a;原因分析…文章目录Java面试必看如何让Main线程成为最后一个退出的秘密一、问题背景为什么我们要关心Main线程的退出顺序二、常见的误区为什么直接运行代码会导致Main线程提前退出示例代码原因分析三、解决方案如何让Main线程等待所有子线程完成方法一使用join()方法修改后的代码运行结果方法二使用守护线程修改后的代码运行结果方法三使用线程池和Future修改后的代码运行结果方法四使用CompletableFuture修改后的代码运行结果四、总结希望这篇文章对你理解如何让Main线程等待子线程完成有所帮助 领取 | 1000 套高质量面试题大合集无套路闫工带你飞一把Java面试必看如何让Main线程成为最后一个退出的秘密大家好我是闫工今天我们要聊一个看似简单但其实非常重要的Java面试知识点——如何确保Main线程成为最后一个退出的线程。这个问题在面试中经常被提及尤其是对于那些有经验或者正在准备进阶的开发者来说。不过别担心我会用一种轻松幽默的方式带大家一步步弄清楚这个问题。一、问题背景为什么我们要关心Main线程的退出顺序首先我们需要明确一个问题Main线程到底是什么在Java中当你运行一个程序时JVM会默认创建一个主线程也就是我们常说的Main线程它负责执行main()方法中的代码。而Main线程的结束就意味着整个程序的结束。但问题来了如果我们启动了多个子线程这些子线程可能在完成任务后继续运行一段时间甚至可能会在Main线程结束后仍然运行。然而有时候我们需要确保Main线程是最后一个退出的尤其是在一些需要优雅关闭或者资源回收的场景中。举个例子假设我们有一个程序它启动了多个后台线程来处理任务而Main线程负责初始化这些线程并监控它们的状态。如果我们希望Main线程在所有子线程完成任务后才退出这就需要一些巧妙的线程管理技巧。二、常见的误区为什么直接运行代码会导致Main线程提前退出很多开发者刚开始接触多线程编程时会发现一个奇怪的现象他们启动了多个线程但Main线程却在所有子线程完成任务之前就退出了。为什么会这样呢让我们通过一个小例子来理解这个问题。示例代码publicclassMainThreadExit{publicstaticvoidmain(String[]args){System.out.println(Main thread is starting...);Threadthread1newThread(()-{try{Thread.sleep(2000);System.out.println(Thread 1 has finished!);}catch(InterruptedExceptione){e.printStackTrace();}});Threadthread2newThread(()-{try{Thread.sleep(3000);System.out.println(Thread 2 has finished!);}catch(InterruptedExceptione){e.printStackTrace();}});thread1.start();thread2.start();System.out.println(Main thread has exited.);}}运行这段代码你会看到以下输出Main thread is starting... Main thread has exited. Thread 1 has finished! Thread 2 has finished!从结果可以看到Main线程在启动两个子线程后立即退出了而没有等待这两个子线程完成任务。为什么会这样呢原因分析简单来说这是因为Main线程只是启动了这些子线程并没有主动等待它们完成。一旦Main线程执行完自己的代码也就是打印出“Main thread has exited.”它就会自动退出。而此时的两个子线程仍然在后台运行。三、解决方案如何让Main线程等待所有子线程完成既然问题出现在Main线程没有等待子线程完成那我们就要想办法让Main线程主动等待这些子线程完成任务后再退出。接下来我会介绍几种常见的方法来实现这一点。方法一使用join()方法最直接的方法就是使用Thread类的join()方法。这个方法的作用是让当前线程这里是Main线程等待调用join()的线程完成后再继续执行。修改后的代码publicclassMainThreadExit{publicstaticvoidmain(String[]args){System.out.println(Main thread is starting...);Threadthread1newThread(()-{try{Thread.sleep(2000);System.out.println(Thread 1 has finished!);}catch(InterruptedExceptione){e.printStackTrace();}});Threadthread2newThread(()-{try{Thread.sleep(3000);System.out.println(Thread 2 has finished!);}catch(InterruptedExceptione){e.printStackTrace();}});thread1.start();thread2.start();// 等待子线程完成try{thread1.join();thread2.join();}catch(InterruptedExceptione){e.printStackTrace();}System.out.println(Main thread has exited.);}}运行结果Main thread is starting... Thread 1 has finished! Thread 2 has finished! Main thread has exited.从结果可以看到Main线程确实在所有子线程完成后才退出了。这种方法简单直接但也有它的缺点当子线程很多时逐一调用join()可能会显得有些笨拙。方法二使用守护线程另一种方法是将子线程设置为守护线程Daemon Thread。守护线程的特点是它不会阻止JVM的退出。换句话说如果所有的非守护线程都已经退出那么守护线程会自动退出。修改后的代码publicclassMainThreadExit{publicstaticvoidmain(String[]args){System.out.println(Main thread is starting...);Threadthread1newThread(()-{try{Thread.sleep(2000);System.out.println(Thread 1 has finished!);}catch(InterruptedExceptione){e.printStackTrace();}});Threadthread2newThread(()-{try{Thread.sleep(3000);System.out.println(Thread 2 has finished!);}catch(InterruptedExceptione){e.printStackTrace();}});// 将子线程设置为守护线程thread1.setDaemon(true);thread2.setDaemon(true);thread1.start();thread2.start();System.out.println(Main thread has exited.);}}运行结果Main thread is starting... Main thread has exited. Thread 1 has finished! Thread 2 has finished!从结果可以看到Main线程在打印“Main thread has exited.”后立即退出了而两个子线程仍然继续运行。但需要注意的是守护线程并不能保证在所有情况下都能优雅地退出因为它们可能会被JVM强制终止。方法三使用线程池和Future如果你使用的是线程池来管理线程那么可以通过Future对象来等待所有任务完成后再退出。修改后的代码importjava.util.concurrent.ExecutorService;importjava.util.concurrent.Executors;importjava.util.concurrent.Future;publicclassMainThreadExit{publicstaticvoidmain(String[]args)throwsException{System.out.println(Main thread is starting...);ExecutorServiceexecutorExecutors.newFixedThreadPool(2);Future?future1executor.submit(()-{try{Thread.sleep(2000);System.out.println(Thread 1 has finished!);}catch(InterruptedExceptione){e.printStackTrace();}});Future?future2executor.submit(()-{try{Thread.sleep(3000);System.out.println(Thread 2 has finished!);}catch(InterruptedExceptione){e.printStackTrace();}});// 等待所有任务完成future1.get();future2.get();executor.shutdown();System.out.println(Main thread has exited.);}}运行结果Main thread is starting... Thread 1 has finished! Thread 2 has finished! Main thread has exited.这种方法比逐一调用join()更优雅特别是在处理大量线程时。方法四使用CompletableFuture如果你在Java 8及以上版本中工作可以考虑使用CompletableFuture来简化代码。修改后的代码importjava.util.concurrent.CompletableFuture;publicclassMainThreadExit{publicstaticvoidmain(String[]args)throwsException{System.out.println(Main thread is starting...);CompletableFutureVoidfuture1CompletableFuture.runAsync(()-{try{Thread.sleep(2000);System.out.println(Thread 1 has finished!);}catch(InterruptedExceptione){e.printStackTrace();}});CompletableFutureVoidfuture2CompletableFuture.runAsync(()-{try{Thread.sleep(3000);System.out.println(Thread 2 has finished!);}catch(InterruptedExceptione){e.printStackTrace();}});// 等待所有CompletableFuture完成CompletableFuture.allOf(future1,future2).join();System.out.println(Main thread has exited.);}}运行结果Main thread is starting... Thread 1 has finished! Thread 2 has finished! Main thread has exited.这种方法不仅代码简洁而且支持更复杂的异步操作。四、总结通过以上几种方法我们都可以实现让Main线程在所有子线程完成后才退出。选择哪种方法取决于具体的场景和需求如果需要简单直接的控制可以使用join()方法。如果是大规模的任务处理建议使用线程池结合Future或CompletableFuture来管理任务。希望这篇文章对你理解如何让Main线程等待子线程完成有所帮助 领取 | 1000 套高质量面试题大合集无套路闫工带你飞一把成体系的面试题无论你是大佬还是小白都需要一套JAVA体系的面试题我已经上岸了你也想上岸吗闫工精心准备了程序准备面试想系统提升技术实力闫工精心整理了1000 套涵盖前端、后端、算法、数据库、操作系统、网络、设计模式等方向的面试真题 详细解析并附赠高频考点总结、简历模板、面经合集等实用资料✅ 覆盖大厂高频题型✅ 按知识点分类查漏补缺超方便✅ 持续更新助你拿下心仪 Offer免费领取 点击这里获取资料已帮助数千位开发者成功上岸下一个就是你✨

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询