线程池是什么,线程池及其原理

学习线程时,我们描述了一个多线程的 Web 服务器,每当服务器接收到一个请求时,它都会创建一个单独线程来处理请求。虽然创建一个单独线程肯定优于创建一个单独进程,但是多线程服务器仍然有些潜在的问题。

第一个问题是创建线程所需的时间多少,以及线程在完成工作之后会被丢弃的事实。第二个问题更为麻烦,如果允许所有并发请求都通过新线程来处理,那么我们没有限制系统内的并发执行线程的数量。无限制的线程可能耗尽系统资源,如 CPU 时间和内存。解决这个问题的一种方法是使用线程池。

线程池的主要思想是:在进程开始时创建一定数量的线程,并加到池中以等待工作。当服务器收到请求时,它会唤醒池内的一个线程(如果有可用线程),并将需要服务的请求传递给它。一旦线程完成了服务,它会返回到池中再等待工作。如果池内没有可用线程,那么服务器会等待,直到有空线程为止。

线程池具有以下优点:
  1. 用现有线程服务请求比等待创建一个线程更快。
  2. 线程池限制了任何时候可用线程的数量。这对那些不能支持大量并发线程的系统非常重要。
  3. 将要执行任务从创建任务的机制中分离出来,允许我们采用不同策略运行任务。例如,任务可以被安排在某一个时间延迟后执行,或定期执行。

池内线程的数量可以通过一些因素来加以估算,如系统 CPU 的数量、物理内存的大小和并发客户请求数量的期望值等。更为高级的线程池架构可以根据使用模式动态调整池内线程数量。这类架构在系统负荷低时,提供了较小的池,从而减低内存消耗(如 Apple的大中央调度)。

Windows API 提供了与线程池有关的多个函数。使用线程池 API 类似于通过函数 Thread_Create() 来创建线程,参见《线程库》一节。这里,定义一个函数,以作为单独线程来运行。这样一个函数如下所示:
DWORD WINAPI PoolFunction(AVOID Param) {
    /*
    * this function runs as a separate thread.
    */
}
PoolFunction() 的指针会被传给线程池 API 中的一个函数,池内的某个线程会执行该函数。线程池 API 的一个这种函数为 QueueUserWorkItem(),它需要三个参数:
  • LPTHREAD START ROUTINE Function:作为一个单独线程来运行的函数的指针。
  • PVOID Param:传递给 Function 的参数。
  • ULONG Flags:标志,用于指示多线程池如何创建线程和管理线程执行。

调用这个函数的示例如下:
QueueUserWorkItem(&PoolFunction, NULL, 0);
这让线程池的一个线程代替程序员来调用 PoolFunction()。这里,我们没有传递参数给 PoolFunction()。由于标志设为 0,因此针对线程池如何创建线程,没有特殊指令。

Windows 线程池 API 还包括可周期性地调用函数,或在一个异步 I/O 请求结束时调用函数。Java API 的 java.util.concurrent 也提供了线程池支持。

推荐文章
Unity 3D Color控件

Unity3DColor控件与BackgroundColor控件类似,都是渲染GUI颜色的,但是两者不同的是Color不但会渲染GUI的背景颜色,同时还会影响GUI.Text的颜色。 具体使用时,要

Apache基金会的Archiva服务器的搭建步骤

在以前的案例开发过程中,曾强烈要求同外网保存连接,为什么呢? 因为一旦开发需要的依赖在本地环境中不存在,Maven会自动到网上的资源仓库中查找,并且下载。基于这种情况,需要在公司搭建一台服务器。程序

java学多久可以找到工作?

Java行业是很注重技术的行业,所以想找一份满意的工作的话,需要求职者掌握一定的Java技术。所以零基础想转行Java的话就需要先学习Java,那么Java学多久可以找到工作呢?首先如果你要自学Jav

Java正则表达式

正则表达式是一种可以用于模式匹配和替换的规范,一个正则表达式就是由普通的字符(如字符a~z)以及特殊字符(元字符)组成的文字模式,它用以描述在查找文字主体时待匹配的一个或多个字符串。 正则表达式作为

Eclipse+PyDec运行Python程序

本节仍以第一个Python程序为例,继续讲解如何通过Eclipse+PyDev实现编写和运行Python程序。 Eclipse创建Python项目 和PyCharm一样,在Eclipse中也是通过项

Struts2内建拦截器

Struts2框架中内置了许多拦截器,这些拦截器以name-class对的形式配置在struts-default.xml文件中,其中,name是拦截器的名称,也就是引用的名字;class指定了该拦截器

Java运算符优先级

所有的数学运算都认为是从左向右运算的,Java语言中大部分运算符也是从左向右结合的,只有单目运算符、赋值运算符和三目运算符例外,其中,单目运算符、赋值运算符和三目运算符是从右向左结合的,也就是从右向左

Hibernate cache.use_second_level_cache属性:判断是否关闭二级缓存

hibernate.cache.use_second_level_cache属性用于指定是否彻底关闭所有二级缓存。 语法: hibernate.cache.use_second_level_cac

Java Servlet Filter(过滤器)是什么?它的方法有哪些?

Filter是Servlet的过滤器,是Servlet2.3规范中新增加的一个功能,主要用于完成一些通用的操作,如编码的过滤、判断用户的登录状态等。 在现实生活中,人们可以使用污水净化设备对水源进行

C语言结构体指针(指向结构体的指针)详解

当一个指针变量指向结构体时,我们就称它为结构体指针。C语言结构体指针的定义形式一般为: struct结构体名*变量名; 下面是一个定义结构体指针的实例: //结构体 structstu{ c

Shell for循环和for int循环详解

除了while循环和until循环,Shell脚本还提供了for循环,它更加灵活易用,更加简洁明了。Shellfor循环有两种使用形式,下面我们逐一讲解。 C语言风格的for循环 C语言风格的for

结构型模式应用实验

结构型模式(StructuralPattern)描述如何将类或者对象结合在一起形成更大的结构,就像搭积木,可以通过简单积木的组合形成复杂的、功能更为强大的结构。结构型模式可以分为类结构型模式和对象结构

Unity 3D物理引擎简介

早期的游戏并没有强调物理引擎的应用,当时无论是哪一种游戏,都是用极为简单的计算方式做出相应的运算就算完成物理表现,如超级玛丽和音速小子等游戏。 较为常见的物理处理是在跳跃之后再次落到地上,并没有特别

MySQL为什么需要事务?

在银行业务中,有一条记账原则,即有借有贷,借贷相等。为了保证这种原则,每发生一笔银行业务,就必须确保会计账目上借方科目和贷方科目至少各记一笔,并且这两笔账要么同时成功,要么同时失败。如果出现只记录了借

第一个TensorFlow程序(hello world)详解

在任何计算机语言中学习的第一个程序是都是Helloworld,本教程中也将遵守这个惯例,从程序Helloworld开始。 上一节进行TensorFlow安装验证的代码如下:     下面一起看

cellular-z是什么?

cellular-z是一款电信小区、信号质量及WIFI网络信息、信道查看软件,主要功能如下:1、双卡手机网络信息查看(SIM卡信息、服务小区信息、服务小区信号质量,部分手机可获取邻小区信息)。2、WI

Java逻辑运算符(&&、||和!)

逻辑运算符把各个运算的关系表达式连接起来组成一个复杂的逻辑表达式,以判断程序中的表达式是否成立,判断的结果是true或false。 逻辑运算符是对布尔型变量进行运算,其结果也是布尔型,具体如表1所示

深度优先生成树和广度优先生成树(详解版)

前面已经给大家介绍了有关生成树和生成森林的有关知识,本节来解决对于给定的无向图,如何构建它们相对应的生成树或者生成森林。 其实在对无向图进行遍历的时候,遍历过程中所经历过的图中的顶点和边的组合,就是

Java包(package)详解

在编写Java程序时,随着程序架构越来越大,类的个数也越来越多,这时就会发现管理程序中维护类名称也是一件很麻烦的事,尤其是一些同名问题的发生。有时,开发人员还可能需要将处理同一方面的问题的类放在同一个

MySQL注释:单行注释和多行注释

MySQL MySQL单行注释## #注释内容# #从结果中删除重复行 SELECTDISTINCTproduct_id,purchase_price FROMProduct;---- --注释内容-