线程池分析(一)
为什么要有线程池?
构建服务器应用程序的简单的模型:当一个请求到达就创建一个新线程,然后在新线程中为请求服务。但实际上服务器应用程序中经常出现的情况是:单个任务处理的时间很短而请求的数目却是巨大的。
于是这样的处理方式极大的耗费资源,影响效率。至于原因则在于线程本身:
线程要素:
1、线程内核对象(thread kernel object)OS为系统中创建的每个线程都分配并初始化这种数据结构之一。在该数据结构中,包含一组对线程进行描述的属性。数据结构中还包含所谓的线程上下文。上下文是一个内存块,其中包含了CPU的寄存器集合。
2、程环境块(thread environment block,TEB)TEB是在用户模式(应用程序代码能够快速访问的地址空间)中分配和初始化的一个内存块。
3、用户模式栈用于存储传给方法的局部变量和实参。它还包含一个地址,指向当前方法返回时,线程接着应该从什么地方开始执行。默认情况下,Windows为每个线程的用户模式栈分配1MB的内存。
4、内核模式栈 应用程序代码向操作系统中的一个内核模式的函数传递实参时,还会使用内核模式栈。出于安全方面的原因,针对从用户模式的代码传递给内核的任何实参,Windows都会把它们从线程的用户
模式栈复制到线程的内核模式栈。一经复制,内核就可验证实参的值。由于应用程序代码不能访问内核模式栈,所以应用程序无法修改验证之后的实参值。OS内核代码将开始对复制的值进行处理。除此之外,内核会调用它自己内部的方法,并利用内核模式栈传递它自己的实参、存储函数的局部变量以及返回地址。
5、DLL线程附加(attach)和线程分离(detach)通知 Windows的一个策略,任何时候在进程中创建一个线程,都会调用那个进程中加载的所有DLL的DLLMain方法,并向该方法传递一个DLL_THREAD_ATTACH标志。类似地,任何时候一个线程终止,都会调用进程中的所有DLL的DLLMain方法,并向该方法传递一个DLL_THREAD_DETACH标志。
所有的DLL需要利用这些通知,为进程中创建/销毁的每个线程执行一些特殊的初始化或资源清理操作。
一个请求对应一个线程带来的问题是:
1、为每个请求创建一个新线程的开销很大,为每个请求创建新线程的服务器在创建和销毁线程上花费的时间和消耗的系统资源要比花在处理实际的用户请求的时间和资源更多。除了创建和销毁线程的开销之外,活动的线程也消耗系统资源。
**活动线程:已启动并且尚未正常终止或中止的线程
因此在一个JVM 里创建太多的线程可能会导致系统由于过度消耗内存而用完内存或“切换过度”。
2、操作系统创建线程、切换线程状态、终结线程都要进行CPU调度,这是一个耗费时间和系统资源的事情。所以如果我们为每一个请求都单独创建一个线程,那么物理机的所有资源基本上都被操作系统创建线程、切换线程状态、销毁线程这些操作所占用,用于业务请求处理的资源反而减少了。
3、线程池作用:线程池通过对多个任务重用线程,线程创建的开销被分摊到了多个任务上。其好处是,因为在请求到达时线程已经存在,所以无意中也消除了线程创建所带来的延迟。这样,就可以立即为请求服务,使应用程序响应更快。而且,通过适当地调整线程池中的线程数目,将处理请求的线程数量控制在一个范围,既保证后续的请求不会等待太长时间,又保证物理机将足够的资源用于请求处理本身。也就是当请求的数目超过某个阈值时,就强制其它任何新到的请求一直等待,直到获得一个线程来处理为止,从而可以防止资源不足。
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 关于Hive使用的一些实例
- 134. 加油站 Krains 2020-08-20 14:03:21 前缀和贪心
- 53. 最大子序和 Krains 2020-08-20 10:46:24 动态规划前缀和
- 如何用Unity导出H5与小游戏的3D场景
- 设计模式 之 模板模式
- java基础:注解的定义与使用
- 使用 vagrant 从搭建 gitlab server 开始体验整个 gitlab CI/CD 过程
- 纲手推荐程序笔记1-p5.js创意游戏编程
- 由浅入深彻底了解 Python 闭包和装饰器
- leetcode1078 Occurrences After Bigram
- 负二进制加法实现
- 如何在O(1)时间复杂度下实现LRU
- 字符串拼接的N种方式
- MySQL 解决查询NULL的问题
- 矩阵旋转的解决