上一篇地址:赶紧收藏!2024 年最常见 100道 Java 基础面试题(二十二)-CSDN博客
四十五、线程池都有哪些状态?
在Java中,线程池(ThreadPoolExecutor
)的状态与Java的线程状态是不同的。线程池的状态主要指的是线程池的生命周期状态,它定义了线程池对提交的任务的处理方式。以下是线程池的几种状态:
-
运行(Running):
- 在这个状态下,线程池可以接受新的任务,也可以处理阻塞队列中的等待任务。
-
关闭(Shutting Down):
- 线程池的
shutdown()
方法被调用后,线程池进入关闭状态。此时,线程池不再接受新任务,但会处理阻塞队列中的已提交任务。
- 线程池的
-
停止(Stop):
- 当调用线程池的
shutdownNow()
方法时,线程池会尝试停止处理等待任务,并尝试停止所有正在执行的任务。此时线程池的状态是停止。shutdownNow()
会尝试立即停止所有活动执行的任务。
- 当调用线程池的
-
阻塞(Blocked):
- 线程池的状态并不包括阻塞,但如果所有线程都忙碌,且队列已满,那么线程池在处理任务时可能会表现出阻塞的特性。
-
终止(Terminated):
- 线程池在执行完所有提交的任务后,可以变为终止状态。线程池的
isTerminating()
方法可以用来判断线程池是否在终止过程中。
- 线程池在执行完所有提交的任务后,可以变为终止状态。线程池的
-
等待(Waiting):
- 线程池的状态并不包括等待,但线程池中的线程在没有任务可执行时,会处于等待状态,直到有新的任务到来或线程池被关闭。
线程池状态转换和相关方法:
- 启动:当线程池被创建,并且至少有一条线程在运行时,线程池就处于运行状态。
- 关闭:调用
shutdown()
方法会关闭线程池,不再接受新任务,但会处理队列中的等待任务。 - 立即停止:调用
shutdownNow()
方法会让线程池尝试立即停止,并中断正在执行的任务。 - 终止:当线程池中的所有任务都已完成,且所有线程都已停止时,线程池变为终止状态。
示例代码:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
public class ThreadPoolStatusExample {
public static void main(String[] args) {
ExecutorService executor = new ThreadPoolExecutor(
3, // core pool size
10, // maximum pool size
60L, // keep-alive time
TimeUnit.SECONDS, // time unit
new LinkedBlockingQueue<Runnable>() // work queue
);
// 关闭线程池,不再接受新任务,但处理等待任务
executor.shutdown();
// 尝试立即停止,中断正在执行的任务
executor.shutdownNow();
// 判断线程池是否终止
((ThreadPoolExecutor) executor).isTerminating();
}
}
总结:
- 线程池的状态反映了线程池的生命周期,从运行到关闭,再到终止。
- 线程池的状态转换由相应的线程池控制方法触发,如
shutdown()
和shutdownNow()
。 - 了解线程池的状态对于正确管理线程池和任务调度非常重要。
四十六、线程池中submit()
和execute()
方法有什么区别?
在Java的java.util.concurrent
包中,ThreadPoolExecutor
类提供了两个关键的方法来提交任务:submit()
和execute()
。这两个方法都用于向线程池提交任务,但它们之间存在一些差异:
-
返回类型:
submit()
方法的返回类型是Future<?>
,它允许你获取任务执行的结果,或者在任务完成前取消任务。execute()
方法不接受返回值,也不提供Future
对象,因此你无法通过它来获取任务的执行结果或取消任务。
-
任务结果:
- 使用
submit()
方法,你可以获取任务执行的结果,特别是当任务是一个Callable
对象时。这使得submit()
适用于那些需要返回值的异步任务。 execute()
方法主要用于那些不需要返回结果的Runnable
任务。
- 使用
-
异常处理:
- 在
submit()
方法中,如果任务在执行过程中抛出异常,异常会被捕获并作为Future
的一部分,你可以通过调用Future.get()
方法来获取这个异常。 - 在
execute()
方法中,如果任务抛出异常,异常会由线程池内部处理,除非线程池的RejectedExecutionHandler
有特殊的处理逻辑,否则你无法直接感知到这个异常。
- 在
-
任务调度:
submit()
方法可以用于执行Callable
和Runnable
任务,而execute()
方法只能执行Runnable
任务。
-
线程池关闭后的行为:
- 当线程池关闭后,
submit()
方法会抛出RejectedExecutionException
,因为它尝试向线程池提交任务。 execute()
方法在线程池关闭后的行为取决于线程池的状态和具体实现,但通常也会拒绝新任务的提交。
- 当线程池关闭后,
-
示例代码:
-
import java.util.concurrent.*; public class ThreadPoolSubmitExecuteExample { public static void main(String[] args) { ExecutorService executorService = Executors.newFixedThreadPool(3); // 使用submit()提交任务 Future<?> future = executorService.submit(() -> { System.out.println("Task submitted with a Future"); }); // 可以调用future.get()来获取任务执行结果或异常 // 使用execute()提交任务 executorService.execute(() -> { System.out.println("Task executed without a Future"); }); // 不能获取任务执行结果或取消任务 executorService.shutdown(); } }
总结:
submit()
方法适用于需要获取任务结果或对任务进行取消的场景,它返回一个Future
对象。execute()
方法适用于不需要任务结果的简单任务执行,它不返回任何内容。- 在设计线程池任务提交逻辑时,应根据任务是否需要返回结果或是否需要支持任务取消来选择合适的方法。