Java 5以Executor框架的形式在Java中引入了线程池,它允许Java程序员将任务提交与任务执行分离。 如果要使用Java进行服务器端编程,则线程池是维护系统可伸缩性,鲁棒性和稳定性的重要概念。 对于那些不熟悉Java中的线程池或这里的线程池的概念的人来说,Java中的线程池是工作线程的池,可以执行提供给他们的任何任务,主要是通过Runnable的实现形式或Callable接口。 由于Java支持编程语言本身中的多线程,因此它允许多个线程同时运行并执行任务的并行处理。 在本文中,我们将学习有关Java线程池的以下内容:
- Java中的线程池是什么?
- 为什么我们需要Java中的线程池?
- Java 5中的Executor框架是什么?
- 如何使用Java中的Executor框架创建固定大小的线程池?
- 在Java中使用线程池的好处?
什么是Java中的线程池以及我们为什么需要它
正如我所说的,线程池是已经创建好的工作线程池,准备好执行此工作。 线程池是任何多线程服务器端Java应用程序都需要的基本功能之一。 使用线程池的一个示例是创建一个处理客户端请求的Web服务器。 如果您熟悉套接字编程,那么您将知道ServerSocket.accept()正在阻塞方法并一直阻塞 ,直到建立套接字连接为止。 如果仅使用一个线程来处理客户端请求,则它将随后限制可以同时访问服务器的客户端数量。 为了支持大量客户端,您可以决定每个请求范例使用一个线程,其中每个请求由单独的线程处理,但这要求在请求到达时创建线程。 由于创建线程是耗时的过程,因此会延迟请求处理。 它还根据每个JVM允许的线程数限制客户端的数量,这显然是有限的。 线程池为您解决了这个问题,它创建了线程并对其进行管理。 线程池不是以创建线程并在完成任务后将其丢弃的方式,而是以工作线程的形式重用线程。 由于通常在应用程序启动时创建并池化线程,因此您的服务器可以立即开始请求处理,这可以进一步缩短服务器的响应时间。 除此之外,在Java应用程序中使用线程池还有其他好处,我们将在下一部分中看到。 简而言之,我们需要线程池来更好地管理线程并将任务提交与执行分离。 Java 5中引入的线程池和Executor框架是库提供的出色线程池。
Java线程池– Java 5中的执行器框架
Java 5引入了一些有用的功能(例如Enum , 泛型 , 变量参数)以及多个并发集合和实用程序(例如ConcurrentHashMap和BlockingQueue等),还引入了完整功能的内置线程池框架(通常称为Executor框架) 。 该线程池框架的核心是Executor接口,该接口使用方法execute(Runnable task)定义任务执行的抽象; ExecutorService扩展了Executor以添加各种生命周期和线程池管理功能,例如关闭线程池。 Executor框架还提供了一个称为Executors的静态实用程序类 (类似于Collections), 该类提供了几种静态工厂方法来创建Java中各种类型的线程池实现,例如固定大小的线程池,缓存的线程池和计划的线程池。
Runnable和Callable接口用于表示由这些线程池中管理的工作线程执行的任务。 Executor框架的有趣之处在于,它基于Producer使用者设计模式 ,其中应用程序线程产生任务和worker线程使用者或执行那些任务,因此,它也遭受了Producer使用者任务的限制,例如生产速度大大高于消耗。当然,仅当您的队列不受限制时,您才可能因为排队的任务而运行OutOfMemory。
如何使用Java中的Executor框架创建固定大小的线程池?
由于Executors类提供了静态工厂方法,因此使用Java 5 Executor框架创建固定大小的线程池非常容易。 您需要做的就是定义要同时执行的任务,然后将该任务提交给ExecutorService。 通过它们,线程池将负责如何执行该任务,它可以由任何空闲的工作线程执行,并且如果您对结果感兴趣,则可以查询Submit()方法返回的Future对象。 Executor框架还提供了不同类型的线程池,例如SingleThreadExecutor仅创建一个工作线程,或者CachedThreadPool在需要时创建工作线程。 您也可以查看Executor框架的Java文档以获取此API提供的服务的完整详细信息。 实践中的Java并发性还有两章专门介绍Java 5 Executor框架的有效使用,这对任何高级Java开发人员都值得一读。
Java中的线程池示例
这是Java中的线程池的示例,该示例使用Java 5的Executor框架创建工作线程数为10的固定线程池。它将创建任务并将其提交到线程池以执行:
public class ThreadPoolExample {
public static void main(String args[]) {
ExecutorService service = Executors.newFixedThreadPool(10);
for (int i =0; i<100; i++){
service.submit(new Task(i));
}
}
}
final class Task implements Runnable{
private int taskId;
public Task(int id){
this.taskId = id;
}
@Override
public void run() {
System.out.println("Task ID : " + this.taskId +" performed by "
+ Thread.currentThread().getName());
}
}
Output:
Task ID : 0 performed by pool-1-thread-1
Task ID : 3 performed by pool-1-thread-4
Task ID : 2 performed by pool-1-thread-3
Task ID : 1 performed by pool-1-thread-2
Task ID : 5 performed by pool-1-thread-6
Task ID : 4 performed by pool-1-thread-5
如果查看此Java示例的输出,则会发现线程池中正在执行任务的线程不同。
Java线程池的好处
线程池为Java应用程序提供了几项好处,其中最大的好处是将任务提交与任务执行分离开来,如果紧密耦合的创建和执行模式比紧密耦合的创建和执行模式更为松散,则可以实现。 这是在Java中使用线程池的更多好处:
- 线程池的使用通过避免在请求或任务处理期间创建线程来减少响应时间。
- 使用线程池可让您根据需要更改执行策略。 您只需替换ExecutorService实现即可从单线程切换到多线程。
- Java应用程序中的线程池通过创建基于系统负载和可用资源决定的配置数量的线程来提高系统的稳定性。
- 线程池使应用程序开发人员摆脱了线程管理的束缚,并专注于业务逻辑。
以上就是Java 5中的线程池。我们已经了解了Java中的线程池,Java 5中的执行者框架,如何在Java中创建线程池以及在Java应用程序中使用线程池的一些好处。 毫无疑问,线程池的知识对于服务器端核心Java开发人员至关重要,我建议阅读Java中的Java线程和并发实践以了解有关并发和线程池的更多信息。
本文推荐书籍
- Brian Goeatz,Doug Leaa,Joshua Bloch和团队的实践中的Java并发
- Java线程,作者:Scott Oaks和Henry Wong
- Joshua Bloach撰写的有效Java