以前的博客中,有说到性能测试常见术语:链接池。其中大概简述了链接池的做用等,这篇博客,就介绍下链接池以及链接池中线程对象的原理,做用以及优势。。。html
1、链接池git
一、什么是链接池?咱们为何须要它?github
链接池容许多个客户端使用缓存起来的链接对象,这些对象能够链接数据库,它们是共享的、可被重复使用的。算法
打开/关闭数据库链接开销很大,链接池技术容许咱们在链接池里维护链接对象,这样能够提升数据库的执行命令的性能。多个客户端请求能够重复使用相同的链接对象,当每次收到一个客户端请求时,数据库
就会搜索链接池,看看有没有闲置链接对象。若是没有,要么全部的客户端请求都进入队列排队,要么在池中建立一个新的链接对象(这取决于池里已有多少个链接存在以及配置支持多少链接)。缓存
一旦某个请求使用完链接对象以后,这个对象会被从新放入池中,而后会被从新分派给排队等待的请求(分派给哪一个请求要看使用什么调度算法)。服务器
由于大部分请求都是使用现存的链接对象,因此链接池技术大大减小了等待建立数据库链接的时间,从而减小了平均链接时间。网络
链接池在基于网络的企业级应用中很常见,应用服务器负责建立链接对象、添加它们到链接池中,分派链接对象给请求,回收使用完毕的链接对象,从新将它们放回链接池去。函数
当网络应用建立数据库链接时,应用服务器会从池中取出链接对象,而当它使用完毕以后关闭时,应用服务器又负责将使用完的链接对象放回池中。
PS:也可使用JDBC 1.0/JDBC 2.0 API来获取物理链接(physical connnection),但这种状况很是少见,由于数据库只须要链接一次,不须要链接池的状况。
能够进行配置最大的链接数、最小链接数、最大空闲链接数等,全部这些参数均可以由服务器管理员配置。服务器启动时,固定数量的链接对象(配置的最小链接数)被建立,并添加到链接池中。
当客户端请求消耗完全部的链接对象时,再有新的请求都会建立新的链接对象,它们被添加到链接池再分派给这个新的请求,直到设置的达到最大的链接数。
服务器也会一直查看闲置的链接对象数,当检测到闲置的链接数超过设置值时,服务器会关闭闲置链接,而后它们将被垃圾回收。
链接池是个开放的概念,任何应用均可以使用这个概念,并用本身想要的方式管理它。链接池概念指的是建立、管理、维护链接对象。
但当应用的规模增大时,若是没有一个健壮的链接池机制的话,管理链接是会得愈来愈困难。
所以,创建一个健壮的、可管理的链接池颇有必要。
PS:关于链接池的内容,参考自http://www.importnew.com/8179.html
2、线程&线程池,链接&链接池
线程:程序执行流的最小单元,进程中的一个实体,一个相对独立的、可调度的执行单元,是被系统独立调度和分派的基本单位;
多线程技术,指在一个进程当中能够建立多个线程来“同时”处理多个事务;
线程池:能够理解为缓冲区,因为频繁的建立销毁线程会带来必定的成本,能够预先建立,但不当即销毁,以共享方式为别人提供服务,一来能够提供效率,再者能够控制线程无线扩张。
链接:指一点与另外一点的链接;
链接池:跟线程池有一样的妙处,但链接池能够是基于多线程来实现,也能够经过多进程来实现,也多是单实例的。
举个例子:
Socket在作为服务时,能够同时监听多个客户端链接,那么它的实现原理就有点像“链接池”;每一个客户经过多个端口同时向服务器发送数据,能够认为是多线程,
而服务器可能已经创建好了n个线程来等待同时处理/分析客户端发来的数据,能够为是有个“线程池”。
3、线程的几种状态
线程在必定条件下,状态会发生变化。线程一共有如下几种状态:
一、新建状态(New):新建立了一个线程对象。
二、就绪状态(Runnable):线程对象建立后,其余线程调用了该对象的start()方法。该状态的线程位于“可运行线程池”中,变得可运行,只等待获取CPU的使用权,
即在就绪状态的进程除CPU以外,其它的运行所需资源都已所有得到。
三、运行状态(Running):就绪状态的线程获取了CPU,执行程序代码。
四、阻塞状态(Blocked):阻塞状态是线程由于某种缘由放弃CPU使用权,暂时中止运行。直到线程进入就绪状态,才有机会转到运行状态。
阻塞的状况分三种:
①.等待阻塞:运行的线程执行wait()方法,该线程会释放占用的全部资源,JVM会把该线程放入“等待池”中。进入这个状态后,是不能自动唤醒的,
必须依靠其余线程调用notify()或notifyAll()方法才能被唤醒,
②.同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入“锁池”中。
③.其余阻塞:运行的线程执行sleep()或join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超时,
或者I/O处理完毕时,线程从新转入就绪状态。
五、死亡状态(Dead):线程执行完了或者因异常退出了run()方法,该线程结束生命周期。
线程变化的状态转换图以下:
PS:拿到对象的锁标记,即为得到了对该对象(临界区)的使用权限。即该线程得到了运行所需的资源,进入“就绪状态”,只需得到CPU,就能够运行。
由于当调用wait()后,线程会释放掉它所占有的“锁标志”,因此线程只有在此获取资源才能进入就绪状态。
下面做下解释:
①.线程的实现有两种方式,一是继承Thread类,二是实现Runnable接口,但无论怎样, 当咱们new了这个对象后,线程就进入了初始状态;
②.当该对象调用了start()方法,就进入就绪状态;
③.进入就绪后,当该对象被操做系统选中,得到CPU时间片就会进入运行状态;
④.进入运行状态后状况就比较复杂;
(1)run()方法或main()方法结束后,线程就进入终止状态;
(2)当线程调用了自身的sleep()方法或其余线程的join()方法,进程让出CPU,而后就会进入阻塞状态(该状态既中止当前线程,但并不释放所占有的资源,
即调用sleep()函数后,线程不会释放它的“锁标志”。)。当sleep()结束或join()结束后,该线程进入可运行状态,继续等待OS分配CPU时间片;
典型地,sleep()被用在等待某个资源就绪的情形;测试发现条件不知足后,让线程阻塞一段时间后从新测试,直到条件知足为止。
(3)线程调用了yield()方法,意思是放弃当前得到的CPU时间片,回到就绪状态,这时与其余进程处于同等竞争状态,OS有可能会接着又让这个进程进入运行状态;
调用 yield() 的效果等价于调度程序认为该线程已执行了足够的时间片从而须要转到另外一个线程。yield()只是使当前线程从新回到可执行状态,
因此执行yield()的线程有可能在进入到可执行状态后立刻又被执行。
(4)当线程刚进入可运行状态(注意,还没运行),发现将要调用的资源被synchroniza(同步),获取不到锁标记,将会当即进入锁池状态,等待获取锁标记
(这时的锁池里也许已经有了其余线程在等待获取锁标记,这时它们处于队列状态,既先到先得),一旦线程得到锁标记后,就转入就绪状态,等待OS分配CPU时间片。
(5)suspend() 和 resume()方法:两个方法配套使用,suspend()使得线程进入阻塞状态,而且不会自动恢复,必须其对应的resume()被调用,才能使得线程从新进入可执行状态。
典型地,suspend()和 resume() 被用在等待另外一个线程产生的结果的情形:测试发现结果尚未产生后,让线程阻塞,另外一个线程产生告终果后,调用resume()使其恢复。
(6)wait()和 notify() 方法:当线程调用wait()方法后会进入等待队列(进入这个状态会释放所占有的全部资源,与阻塞状态不一样),进入这个状态后,是不能自动唤醒的,
必须依靠其余线程调用notify()或notifyAll()方法才能被唤醒(因为notify()只是唤醒一个线程,但咱们由不能肯定具体唤醒的是哪个线程,也许咱们须要唤醒的线程不可以被唤醒,
所以在实际使用时,通常都用notifyAll()方法,唤醒有所线程),线程被唤醒后会进入锁池,等待获取锁标记。
wait() 使得线程进入阻塞状态,它有两种形式:
一种容许指定以ms为单位的时间做为参数,另外一种没有参数。前者当对应的notify()被调用或超出指定时间时线程从新进入可执行状态即就绪状态,后者则必须对应的notify()被调用。
当调用wait()后,线程会释放掉它所占有的“锁标志”,从而使线程所在对象中的其它synchronized数据可被别的线程使用。
waite()和notify()由于会对对象的“锁标志”进行操做,因此它们必须在synchronized函数或synchronizedblock中进行调用。
若是在non-synchronized函数或non-synchronizedblock中进行调用,虽然能编译经过,但在运行时会发生IllegalMonitorStateException的异常。
PS:关于线程的几种状态,转载自开源中国:线程的几种状态