线程池的作用是什么?有好的现实世界的例子吗?
线程池的作用是什么?有好的现实世界的例子吗?
线程池是一组最初被创建的线程,等待任务并执行它们。其思想在于始终保持这些线程的存在,以避免每次创建线程时支付开销时间。当我们知道有一系列要处理的作业时,线程池是合适的选择,即使有时可能没有作业。
以下是来自维基百科的优美图示:
线程池是一个准备就绪的工作线程池,它创建Thread
并管理它们。线程池会重复使用已经创建的线程(即工作线程),而不是在任务完成后创建线程并丢弃它们。
为什么要用线程池?
因为创建线程是一个耗时的过程,它会延迟请求处理。它还限制了客户端的数量,基于每个JVM允许的线程数,这显然是有限制的。
使用Executor框架创建固定大小的线程池 -
Java 5引入了一个完整功能的内置线程池框架,通常称为Executor框架。
使用Java 5 Executor
框架创建固定大小的线程池非常容易,因为Executors
类提供了静态工厂方法。你所需要做的就是定义要并发执行的任务,然后将该任务提交给ExecutorService
。
从这里开始,线程池将负责如何执行该任务;它可以由任何空闲的工作线程执行。
public class ThreadPoolExample {
public static void main(String args[]) {
ExecutorService service = Executors.newFixedThreadPool(10); //create 10 worker threads in Thread Pool
for (int i =0; i<100; i++){
service.submit(new Task(i)); //submit that to be done
}
service.shutdown();
}
}
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
*Output may vary from system to system
Java教程中的线程池提供了一个很好的概述:
使用工作线程最小化了由于线程创建而产生的开销。线程对象使用大量内存,在大规模应用程序中,分配和释放许多线程对象会产生显著的内存管理开销。
线程池只在服务器-客户端情况下有用,其中无法确定/预测客户端请求的数量/发生次数。
在这种情况下,每次客户端请求都创建一个新线程有两个缺点:
1) 线程创建的运行时延迟: 创建线程需要一定时间,因此实际工作不会在请求进入时立即开始。客户可能会注意到轻微的延迟。
在交互式系统中,这一标准至关重要,客户期望立即得到响应。
2) 未受控制地使用系统资源: 线程消耗系统资源(内存等),因此在出现意想不到的客户请求流时,系统可能会耗尽资源。
线程池通过以下方式解决上述问题:
1) 在服务器启动时创建指定数量的线程,而不是在运行时创建它们。
2) 限制同时运行的线程数。
注意:上述内容适用于固定大小的线程池。