线程池高手进阶:揭秘ThreadPoolExecutor的小妙招!- 程序员古德Executor和ExecutorService区别?
Executor和ExecutorService都是Java并发编程中的重要概念,两者都用于异步地执行任务,但是它们之间存在一些重要的区别:
设计目标:
Executor:设计目标是提供一个简单的、统一的、高层次的抽象来执行命令,Executor框架主要用于简化线程管理,包括启动、调度和终止线程。
ExecutorService:设计目标是提供一个更全面的框架,用于管理和控制大量并发的任务,它扩展了Executor接口,提供了更多高级功能,如任务提交、关闭、定期执行等。
生命周期管理:
Executor:没有内置的生命周期管理功能,当提交一个命令时,Executor会立即启动一个新的线程(如果需要),如果想在某个时间点停止执行命令,需要手动实现这一功能。
ExecutorService:提供了内置的生命周期管理功能,可以使用shutdown()或shutdownNow()方法来停止接受新的任务并关闭ExecutorService,已经提交的任务会继续执行,直到完成。
任务提交:
Executor:通过实现Runnable或Callable接口的任务对象来提交任务,Executor没有提供任务结果的处理方式。
ExecutorService:提供了Future和Callable接口的任务提交方式,Future接口使得任务执行者能够异步地获取任务结果。
异常处理:
Executor:没有提供异常处理机制,如果任务抛出未捕获的异常,那么这个异常会被传递给UncaughtExceptionHandler,由系统默认处理。
ExecutorService:允许通过Future的get()方法获取任务的执行结果,如果任务抛出异常,get()方法会抛出ExecutionException,可以通过ExecutionException的getCause()方法获取原始的异常。
线程池:
Executor:没有内置的线程池功能,如果需要使用线程池,需要自己创建并管理线程池。
ExecutorService:是线程池的一种实现方式,它内部封装了一个线程池,通过调用shutdown()或shutdownNow()方法可以关闭线程池。
并行流:
Executor:不是并行流的底层实现,并行流使用的是ForkJoinPool,而不是Executor或ExecutorService。
ExecutorService:可以作为并行流的底层实现,通过将Stream的中间操作和终止操作组合在一起,可以充分利用ExecutorService的并发能力。
适用场景:
Executor:适用于简单的异步任务执行场景,例如启动一个新线程来执行一个简单的计算任务,由于没有生命周期管理、任务结果处理等功能,Executor在复杂的多任务并发场景中可能不够用。
ExecutorService:适用于需要管理大量并发任务、生命周期管理、任务结果处理等功能的场景,例如Web服务器接受客户端请求并处理请求。
总结,Executor是一个相对简单的框架,适用于简单的异步任务执行场景;而ExecutorService提供了更全面的功能,适用于复杂的并发任务管理场景。在实际应用中,通常会使用ExecutorService而不是Executor,因为ExecutorService提供了更多的功能和更好的性能。
使用Executor
下面代码是Executor来执行一个线程,如下:
使用ExecutorService
下面代码是ExecutorService
来执行一个线程,如下:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ExecutorServiceExample {
public static void main(String[] args) {
// 创建一个单线程的ExecutorService
ExecutorService executorService = Executors.newSingleThreadExecutor();
// 提交任务
executorService.submit(() -> {
System.out.println("Task is running in thread: " + Thread.currentThread().getName());
});
}
}
领取专属 10元无门槛券
私享最新 技术干货