转载请注明出处: jiq钦's technical Blog - 季义钦
在Java 5之后,任务分两类:一类是实现了Runnable接口的类,一类是实现了Callable接口的类。两者都可以被ExecutorService执行,但是Runnable任务没有返回值,而Callable任务有返回值。此外还有一个FutureTask任务类型以拓展Runnable和Callable。
(备注:图片转自网络)
一、Runnable任务抽象
考虑一个处理客户端请求的服务器程序:
1.1 Thread方式
通常我们为了提高服务器监听程序的响应能力,并不会在监听主程序中处理接收到的客户端请求,而是在接收到请求之后为其分配一个线程去处理:
class ThreadPerTaskWebServer{
publicstatic void main(String[] args) throws IOException{
ServerSocketsocket = new ServerSocket(8080);
while(true){
fnalSocket connnection = new socket.accept();
Runnabletask = new Runable(){ //匿名类
publicvoid run(){
handleClientRequest(connection);
}
};
new Thread(task).start();
//or rask.run();
}
}
}
1.2 线程池
1.2.1 线程池抽象Executor
生产环境中,“为每个请求分配一个线程”这种方法存在一定缺陷,尤其是当需要创建大量线程时,主要体现在几个方面:
A 频繁创建和销毁线程代价非常高;
B 过多线程极耗内存。当你有足够多的线程保持CPU忙碌时,更多的线程反而降低性能;
C 稳定性问题。可创建线程数受JVM参数、栈大小等限制,无限制创建线程可能带来异常;
由此java推出了线程池的库,任务执行的抽象从Thread变为Executor,Executor描述的是一个具备特定执行策略的线程池,应用程序只需要简单地将任务提交到线程池,具体的执行策略由具体的线程池实现决定。
class TaskExecutionWebServer{
privatestatic final int SIZE = 100;
privatestatic final Executor exec = Executors.newFixedThreadPool(SIZE);
publicstatic void main(String[] args) throws IOException{
ServerSocketsocket = new ServerSocket(8080);
while(true){