假设一个服务器完成一项任务所需时间为:T1 创建线程时间,T2 在线程中执行任务的时间,T3 销毁线程时间。
如果:T1 + T3 远大于 T2,则可以采用线程池,以提高服务器性能。
一个线程池包括以下四个基本组成部分:
1、线程池管理器(ThreadPool):用于创建并管理线程池,包括 创建线程池,销毁线程池,添加新任务;
2、工作线程(PoolWorker):线程池中线程,在没有任务时处于等待状态,可以循环的执行任务;
3、任务接口(Task):每个任务必须实现的接口,以供工作线程调度任务的执行,它主要规定了任务的入口,任务执行完后的收尾工作,任务的执行状态等;
4、任务队列(taskQueue):用于存放没有处理的任务。提供一种缓冲机制。
线程池技术正是关注如何缩短或调整T1,T3时间的技术,从而提高服务器程序性能的。它把T1,T3分别安排在服务器程序的启动和结束的时间段或者一些空闲的时间段,这样在服务器程序处理客户请求时,不会有T1,T3的开销了。
线程池不仅调整T1,T3产生的时间段,而且它还显著减少了创建线程的数目,看一个例子:
假设一个服务器一天要处理50000个请求,并且每个请求需要一个单独的线程完成。在线程池中,线程数一般是固定的,所以产生线程总数不会超过线程池中线程的数目,而如果服务器不利用线程池来处理这些请求则线程总数为50000。一般线程池大小是远小于50000。所以利用线程池的服务器程序不会为了创建50000而在处理请求时浪费时间,从而提高效率。
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class FixedThreadPoolDemo {
public static void main(String[] args) {
// 创建一个最多同时运行 3 个任务的线程池
ExecutorService service = Executors.newFixedThreadPool(3);
// 安排若干个任务运行
service.execute(new RunnableImpl(1));
service.execute(new RunnableImpl(2));
service.execute(new RunnableImpl(3));
service.execute(new RunnableImpl(4));
service.execute(new RunnableImpl(5));
service.execute(new RunnableImpl(6));
service.execute(new RunnableImpl(7));
service.execute(new RunnableImpl(8));
service.execute(new RunnableImpl(9));
service.execute(new RunnableImpl(10));
service.execute(new RunnableImpl(11));
service.execute(new RunnableImpl(12));
service.execute(new RunnableImpl(13));
service.execute(new RunnableImpl(14));
service.execute(new RunnableImpl(15));
// 结束线程池。shutdown() 不会马上结束,而是等所有安排的任务执行完才结束。
service.shutdown();
// 如果不想马上结束,又不愿意等太长时间,那么可以调用 awaitTermination() 方法等待一段时间
try {
service.awaitTermination(5, TimeUnit.SECONDS);
System.err.println("等待时间已过");
// shutdownNow() 将放弃所有正在等待的任务,等当前执行的任务全部完成之后,结束线程池。
List<Runnable> abandoned = service.shutdownNow();
System.err.println("被遗弃的任务:" + abandoned);
} catch (InterruptedException e) {
e.printStackTrace();
System.exit(-1);
}
}
private static class RunnableImpl implements Runnable {
private int id;
private RunnableImpl(int id) {
this.id = id;
}
public void run() {
System.out.println("开始执行" + id);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// nothing to do
}
System.out.println(id + "执行完毕。");
}
@Override
public String toString() {
return "线程" + id;
}
}
}