现在已经是第二大部分啦-结构化并发应用程序~~
在线程中执行任务
当围绕任务执行来设计应用程序时,第一步就是找出清晰的任务边界。
如果任务是相互独立的那么有助于实现并发。
负载相关性
在正常负载的情况下,应该同时表现出良好的吞吐量和快速的响应性。当负荷过载时,应用程序性能应该是逐渐降低,而不是直接失败。
要实现上述目标,应该选择清晰的任务边界,以及明确的任务执行策略。
大多数服务器以独立的客户请求做为边界,web服务器,数据库服务器,邮件服务器等等。比如说邮件服务器在收到一封邮件的时候 并不影响处理其它邮件。
串行的执行任务
class SingleThread{
public static void main(String [] args){
ServerSocket socket=new ServerSocket(80);
while(true){
Socket connection=socket.accept();
handleRequest(connection);
}
}
}
显式的创建线程
class webserverThread{
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();
}
}
}
这只是举两个极端情况,其实所有复杂的程序都是一个个简单的东西组成的,对于生活亦是如此。
有了串行和并发,我们就可以根据请求的类型,选择处理的反应机制。在任务相对独立的情况下选择并发的创建线程,而相关性较强的可以用前面的阻塞队列等同步工具进行处理。
无限创建线程的不足
当然在web服务器上虽然是相互独立的任务,但也不可能用那么 简单的方法 去创建线程的处理请求
有几个原因如下:
- 线程生命周期的开销非常高。只是相对来说。也许在写程序的时候觉得创建一个线程对程序的运行影响非常小。不过与创建 一个变量相比多很多。
- 资源消耗 活跃的线程会消耗系统资源,尤其是内存。如果可运行的线程数量多于可用处理器的数量那么有些线程将会被闲置。大量空间线程会占用内存,给Gc带来压力。而且在它们抢夺cpu资源的时候还会产生其他性能开销。如果已经有足够多的线程使所有cpu保持忙碌状态,那么再创建更多的线程反而会降低性能。
- 稳定性。对于可创建线程的数量,这个数值随着平台的不同而不同。并受多个因素制约,包括 jvm启动参数,Thread构造函数中的请求栈的大小,以及底层操作系统对线程的限制等等。
executor框架
以前写过,点击打开链接