1.Excutor框架出现的背景
在正常负载情况下,服务器应用程序应该兼具良好的吞吐量和快速的响应性。同时在过载时应平缓的劣化,而不应该负载一高就简单地以失败告终。为了达到这个目的,你要选择一个清晰的任务边界,并配合一个明确的任务执行策略。
1.1顺序化执行任务
看下面的例子:
class SingleThreadWebServer{
public static void main(String[] args){
ServerSocket socket = new ServerSocket(80);
while(true)
Socket connection = socket.accept();
handleRequest(connection);
}
}
}
上面的例子是实现了一个单线程化的Web Server,缺点很明显:只有当主线程处理完当前请求,才能继续接收其他请求。同时单线程化在等待I/O操作时,cpu基本处于闲置状态,因此导致了资源利用率非常低。
顺序化处理几乎不能为服务器应用程序提供良好的吞吐量和快速的用户响应,而且没有任何并发性而言。
1.2 显式为任务创建线程
class ThreadPerTaskWebServer{
public static void main(String[] args){
ServerSocket socket = new ServerSocket(80);
while(true)
final Socket connection = socket.accept();
Runnable task = new Runnable(){
public void run(){
handleRequest(connection);
}
}
new Thread(task).start();
}
}
}
上面的例子为每个socket分配了一个线程,这样主线程可以不断接受连接请求,从而提高响应性和并发性。在中等强度的负载水平下,每线程没任务方法对顺序化执行进行了良好的改进。只要请求的到达速度尚未打到服务器的处理能力,那么这种方法可以同时带来更快的响应性和更大的吞吐量。
1.3无限制创建线程的缺点:
1.线程生命周期的开销:线程的创建和销毁不是免费的,创建线程需要时间,会带来请求的延时,如果请求是大量而且频繁的,每线程每任务会消耗大量的计算资源。
2.内存消耗和cpu消耗:一个线程需要一定的内存,而且会给gc带来压力,同时大量线程会竞争cpu资源,还能产生其他的性能开销。
3.稳定性:每个线程会为栈分配一定的内存,如果打破了操作系统的限制,会收到一个OutOfMemory异常。
2.Excutor框架
无限制线程,有很多缺陷,而有界的线程可以防止资源过载而耗尽内存。作为Excutor的一部分,java.util.concurrent包提供了一个灵活的线程池实现。在java类库中,任务执行的首要抽象不是Thread,而是Excutor:
public interface Executor{
void execute(Runnable command);
}
package executor;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
/**
*
*
Test
Description:
Company:Cisco CAS
Department:CAS