前言
在应用系统开发过程中,我们对于数据库,HttpClient,Java线程池与Tomcat线程池等需要连接或需要先建的资源,在进行连接与创建时也是很耗性能的。所以需要通过池化来减少一些消耗,以提升性能。
比如对象池是通过服用对象从而减少创建对象,垃圾回收的开销,但同时池也不能太大,太大会影响GC时的扫描时间。而连接池是通过复用TCP连接来减少创建和释放连接的时间来提升性能。线程池也是一样的原理,通过复用线程提升性能。池化的作用就是通过复用技术提升性能。
一、数据库连接池
1.不使用连接池
在使用开发基于数据库的web程序时,正常的流程是在主程序(如servlet、beans)中建立数据库连接,然后进行sql操作,sql操作完毕之后,再断开数据库连接。
正常的连接数据库是通过使用 DriverManager 来获取,每次向数据库建立连接的时候都要将 Connection 加载到内存中,再验证用户名和密码(得花费0.05s~1s的时间)。需要数据库连接的时候,就向数据库要求一个,执行完成后再断开连接。这样的方式将会消耗大量的资源和时间。数据库的连接资源并没有得到很好的重复利用.若同时有几百人甚至几千人在线,频繁的进行数据库连接操作将占用很多的系统资源,严重的甚至会造成服务器的崩溃。并且每一次数据库连接,使用完后都得断开。否则,如果程序出现异常而未能关闭,将会导致数据库系统中的内存泄漏,最终将导致重启数据库。
这种开发不能控制被创建的连接对象数,系统资源会被毫无顾及的分配出去,如连接过多,也可能导致内存泄漏,服务器崩溃。
2.使用连接池
数据库连接池的基本思想就是为数据库连接建立一个“缓冲池”。预先在缓冲池中放入一定数量的连接,当需要建立数据库连接时,只需从“缓冲池”中取出一个,使用完毕之后再放回去。同时数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是重新建立一个。
数据库连接池在初始化时将创建一定数量的数据库连接放到连接池中,这些数据库连接的数量是由最小数据库连接数来设定的。无论这些数据库连接是否被使用,连接池都将一直保证至少拥有这么多的连接数量。连接池的最大数据库连接数量限定了这个连接池能占有的最大连接数,当应用程序向连接池请求的连接数超过最大连接数量时,这些请求将被加入到等待队列中。
3.连接池解决的问题
资源重用
由于数据库连接得以重用,避免了频繁创建,释放连接引起的大量性能开销。在减少系统消耗的基础上,另一方面也增加了系统运行环境的平稳性。
更快的系统反应速度
数据库连接池在初始化过程中,往往已经创建了若干数据库连接置于连接池中备用。此时连接的初始化工作均已完成。对于业务请求处理而言,直接利用现有可用连接避免了数据库连接初始化和释放过程的时间开销,从而减少了系统的响应时间。
资源合理分配
新的资源分配手段对于多应用共享同一数据库的系统而言,可在应用层通过数据库连接池的配置实现某一应用最大可用数据库连接数的限制避免某一应用独占所有的数据库资源。
统一的连接管理
避免数据库连接泄露在较为完善的数据库连接池实现中,可根据预先的占用超时设定,强制回收被占用连接,从而避免了常规数据库连接操作中可能出现的资源泄露。
二、HttpClient连接池
1.什么是HttpClient?
HTTP协议
HTTP协议是一个基于TCP的网络通信协议,可以说是现在Internet上面最重要,使用最多的协议之一了。
HttpClient
HttpClient是一个支持 HTTP 协议最新的版本和建议的HTTP通信库(不是浏览器),HttpClient的目标是发送和接收HTTP报文。HttpClient不会去缓存内容,执行嵌入在HTML页面中的javascript代码,猜测内容类型,重新格式化请求/重定向URI,或者其它和HTTP运输无关的功能。因此它只提供一个通用浏览器应用程序所期望的功能子集,最根本的区别是HttpClient中没有用户界面,浏览器需要一个渲染引擎来显示页面。
2.为什么要使用HttpClient连接池呢?
我们都知道,http建立连接的过程是比较繁琐的(因为基于TCP协议),要经历3次握手和4次挥手,那么省去这个建立连接的过程在高并发的时候就会比较的有必要;对于http连接,使用的是tcp的长连接,但是长连接的持有是非常耗资源的,特别是对于服务端,链接数是有限的,所以我们同样需要释放一定时间空闲的连接;
使用HttpClient的好处
降低延迟
如果不采用连接池,每次连接发起Http请求的时候都会重新建立TCP连接(经历3次握手),用完就会关闭连接(4次挥手),如果采用连接池则减少了这部分时间损耗。这样我们再对同一个网址进行请求的时候,就可以不用每次都建立连接。
支持更大的并发
如果不采用连接池,每次连接都会打开一个端口,在大并发的情况下系统的端口资源很快就会被用完,导致无法建立新的连接。
三、线程池
1.什么是线程?
线程,程序执行流的最小执行单位,是进程中的实际运作单位,经常容易和进程这个概念混淆。那么,线程和进程究竟有什么区别呢?简单来说,一个应用程序的运行就可以被看做是一个进程,而线程,是运行中的实际的任务执行者。可以说,进程中包含了多个可以同时运行的线程。而线程又分为多线程于单线程两种模式。
2.单线程与多线程?
单线程
顾名思义即是只有一条线程在执行任务,这种情况在我们日常的工作学习中很少遇到,所以我们只是简单做一下了解。
多线程
创建多条线程同时执行任务,这种方式在我们的日常生活中比较常见。但是,在多线程的使用过程中,还有许多需要我们了解的概念。比如,在理解上并行和并发的区别,以及在实际应用的过程中多线程的安全问题,对此,我们需要进行详细的了解。
并行和并发
在我们看来,都是可以同时执行多种任务,那么,到底他们二者有什么区别呢?
并行
从宏观方面来说,并行就是同时进行多种时间,实际上,这几种时间,并不是同时进行的,而是交替进行的,而由于CPU的运算速度非常的快,会造成我们的一种错觉,就是在同一时间内进行了多种事情。
并发
并发则是真正意义上的同时进行多种事情。这种只可以在多核CPU的基础下完成。
多线程的安全问题
为什么会造成多线程的安全问题呢?我们可以想象一下,如果多个线程同时执行一个任务,那么意味着他们共享同一种资源,由于线程CPU的资源不一定可以被谁抢占到,这是,第一条线程先抢占到CPU资源,他刚刚进行了第一次操作,而此时第二条线程抢占到了CPU的资源,就会产生资源抢占问题。这个问题我们应该如何解决呢?
这个问题主要的矛盾在于,CPU的使用权抢占和资源的共享发生了冲突,解决时,我们只需要让一条线程占用CPU的资源时,阻止第二条线程同时抢占CPU的执行权,同时在方法中使用同步代码块即可。
3.为什么要使用线程池?
在实际项目中,我们需要多次使用线程,也就意味着,我们需要多次创建并销毁线程。而创建并销毁线程的过程势必会消耗内存。而在Java中,内存资源是及其宝贵的,所以就产生线程池。
4.线程池
正是因为多线程每次都需要创建、销毁线程从而占用太多系统资源,所以我们建这么一个池子来统一管理线程。用的时候从池子里拿,不用了就放回来,也不用你销毁,全部由线程池来管理。
使用线程池的好处
降低资源消耗
通过重复利用现有的线程来执行任务,避免多次创建和销毁线程。
提高相应速度
因为省去了创建线程这个步骤,所以在拿到任务时,可以立刻开始执行。
提供附加功能
线程池的可拓展性使得我们可以自己加入新的功能,比如说定时、延时来执行某些线程。
总结
每一个高并发高可用都缺不了细节。而池化就是必不可少的细节。但是在使用池的时候,一定要注意使用完了要回收,不然会造成可用池使用上限,获取池时,等待卡死。
引用: https://blog.csdn.net/qq441568267/article/details/52951767 https://blog.csdn.net/weixin_41948075/article/details/88121930 https://zhuanlan.zhihu.com/p/259624983 https://blog.csdn.net/weixin_38749096/article/details/94416491
|