一、线程池的由来
在服务器编程模型的原理,每一个客户端连接用一个单独的线程为之服务,当与客户端的会话结束时,线程也就结束了,即每来一个客户端连接,服务器端就要创建一个新线程。
如果访问服务器的客户端很多,那么服务器要不断地创建和销毁线程,这将严重影响服务器的性能。
二、线程池的概念和原理
线程池的概念:首先创建一些线程,它们的集合称为线程池,当服务器接受到一个客户请求后,就从线程池中取出一个空闲的线程为之服务,服务完后不关闭该线程,而是将该线程还回到线程池中。
在线程池的编程模式下,任务是提交给整个线程池,而不是直接交给某个线程,线程池在拿到任务后,它就在内部找有无空闲的线程,再把任务交给内部某个空闲的线程,任务是提交给整个线程池,一个线程同时只能执行一个任务,但可以同时向一个线程池提交多个任务。
三、相关的类和方法
从Java5开始提供了线程池的相关类和接口java.util.concurrent.Executors类和java.util.concurrent.ExecutorService接口。
其中Executors是个工具类和线程池的工厂类,可以创建并返回不同类型的线程池,常用方法如下:
其中ExecutorService接口是真正的线程池接口,主要实现类是ThreadPoolExecutor,常用方法如下:
代码演示:
- 使用实现Callable接口的方式创建一个线程,实现1~10000之间的累加和并打印
/**
* Callable接口支持泛型
*/
public class ThreadImplCallable implements Callable {
@Override
public Object call() throws Exception {
// 实现1~10000之间的累加和并打印
int num = 0;
for (int i = 1; i <= 10000; i++) {
num += i;
}
System.out.println(" 累加和为: " + num); // 50005000
return num;
}
public static void main(String[] args) {
ThreadImplCallable tic = new ThreadImplCallable();
FutureTask ft = new FutureTask(tic);
// 创建线程并启动
Thread t1 = new Thread(ft);
t1.start();
Object obj = null;
try {
obj = ft.get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
System.out.println("线程处理的返回值为:" + obj); // 50005000
}
}
- 使用线程池并测试
/**
* 线程池的使用
*/
public class ThreadPoolUseTest {
public static void main(String[] args) {
// 创建线程池:创建一个线程数量固定的线程池 10个线程
ExecutorService executorService = Executors.newFixedThreadPool(10);
// 向先程池中提交任务
Future submit = executorService.submit(new ThreadImplCallable());
System.out.println(submit);
// 关闭线程池
executorService.shutdown();
}
}
四、常见的4种线程池
Executors.newCachedThreadPool();
Executors.newFixedThreadPool(10);
Executors.newScheduledThreadPool(10);
Executors.newSingleThreadExecutor();