1.思考
到目前为止,我们分享了多线程并发编程基础系列,比如说:如何创建线程、线程的启动与停止、常见的线程方法与线程属性等知识点。
掌握了基础系列知识,我们算是入了多线程并发编程的门。但是要想在实际的企业项目中使用并发编程,还有一定的距离。并且我们学习的目的,就是为了应用,对吧,毛爷爷就说过:精通的目的全在于应用。如果一个东西,我们学了而没有机会使用,那么和耍流氓其实是一样的。
也许曾经我们做传统企业项目的IT技术人员,原于业务复杂度,项目体量都比较小,长期担任着CRUD的boy。习惯了使用开源的应用框架,就这么使用着,忽略了框架本身的底层实现,没有动力去关注框架的底层实现,因为不需要,就这么CRUD也挺好。
但是现在时代变了,大时代从消费互联网,转向了产业互联网,原来人互联网人只是toC,现在要toB了,要来抢饭碗了,传统企业们也要数字化转型了。对于我们传统企业的IT技术人员不能再只满足CRUD了,企业要数字化转型,势必会带来更大的业务复杂度,更大的体量,需要技能树更高的技术人员。
虽然现在项目上的事情挺多,几乎都成了996,我想还是决定利用周末有限的时间,把我所知道的多线程并发编程的一些知识,比如说:线程池、锁、并发流程控制、并发编程集合、线程安全的一些底层知识:原子性、可见性、CAS、AQS等。结合我所经历的项目中的一些应用案例,尽量做一些体系化、系统化的梳理分享,既鞭策自己的同时,也能和更多的朋友一起讨论学习。
那么就让我们从今天,从这一篇开始吧!
#考考你:
1.你知道如何创建线程了,那么你知道如何治理它们吗
2.你知道为什么会有池化的概念吗,比如说:连接池、线程池
2.案例
2.1.为什么需要线程池
2.1.1.池化在项目中的应用
在实际的项目中,你一定会经常听到和使用两个与池有关的概念:连接池、线程池。
你们的项目需要操作数据库:mysql或者oracle,大多数 时候,你们一定使用了一些开源的数据库连接池,比如说:dbcp、c3p0、druid。而且你都很熟悉,对吧
或者说你们的项目准备上线了,选择了tomcat作为应用服务器,你一定不会从官网下载下来,解压后直接使用。你们老大会要求说,那谁改一下tomcat的相关配置参数,让这只小猫跑的快一点,其中你一定很熟系下面这个标签的配置:
<connector port="8081" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443">
maxThreads:Tomcat使用线程来处理接收的每个请求。该值表示可创建的最大的线程数
minSpareThreads:最小空闲线程数量
maxSpareThreads:最大空闲线程数量
acceptCount:指定当所有可以使用的处理请求的线程数都被使用时,可以放到处理队列中的请求数,超过这个数的请求将不予处理
enableLookups:是否反查域名,取值为:true或false。为了提高处理能力,应设置为false
connectionTimeout:网络连接超时,单位:毫秒。设置为0表示永不超时,这样设置有隐患的。默认可设置为20000毫秒。
web server允许的最大连接数还受制于操作系统的内核参数设置,通常Windows是2000个左右,Linux是1000个左右
</connector>
其中:maxThreads、minSpareThreads、maxSpareThreads三个属性,即是tomcat线程池相关的配置参数
2.1.2.关于池化的理解
现在你知道了,其实我们一直在项目中使用池化的思想,或者说是解决方案。那么问题来了,为什么一定要池化呢?
要理清这个问题,其实非常简单。我们以线程池为例,你说tomcat不使用线程池可不可以,能不能也正常处理web请求?答案是可以。你说在我们的项目中,需要实现多线程并发编程,每次处理任务,我们都直接创建一个新的线程来处理可不可以?答案是可以。
但是我们需要知道,我们的服务器资源,不管是cpu,还是内存memory都是有限,并且宝贵的资源,然而我们要处理的任务它可能是无限的,这个地方你需要关心:有限的资源。
另外你还需要知道,如果不使用线程池,那么每一次任务我们都需要创建一个新的线程,处理完任务后,我们还需要销毁该线程,因为该线程的使命已经完成了。这个地方你需要关心:每一次都要创建线程、然后销毁线程。
好了,我们可以回答为什么在项目中,需要使用连接池,线程池了。最直观的理由是:
-
服务器资源是有限的,我们需要合理利用有限的资源,处理无限的任务
-
每一次任务,都要创建线程,然后销毁线程。容易造成资源的极度浪费,以jvm为例,创建线程需要申请内存资源,销毁线程需要进行垃圾回收。频繁这么操作,jvm一定会说:我很累,能不能不要那么折腾!
-
于是我们使用线程池,可以复用线程。即一个线程创建并处理完成任务后,先不要销毁,找个地方休息一下。如果有新的任务来了,继续干活
-
这样一来,不需要频繁创建新线程,销毁线程。一方面提升了应用的处理性能,我们高兴了;另外一方面jvm也不会觉得那么折腾,那么累了,皆大欢喜!
-
这就是我们在项目中为什么需要使用线程池:
- 复用线程
- 合理利用有限资源处理无限任务
- 提升应用的业务处理能力与性能