大多数情况下,会出现连接未关闭的问题。 连接无法立即关闭的直接结果是内存泄漏,直到down计算机。 我们也知道解决方法,但解决问题后,我们会仔细考虑为什么会这样。 连接掉close (),制作的话会不会很浪费cpu等系统资源呢? 有更好的方法吗? 我们也经常听到连接池、线程池等线程、池的概念,这些概念与我们的连接有什么关系呢?
那么,我想就以上问题谈一下我的浅见,请您批评指正。
众所周知,java语言是语言级多线程机制的面向对象语言。 例如,java基类object提供了一些线程控制方法,如wati ()、notify ()和notifyall ()。 如果您已经了解了操作系统的变化,应该知道线程存在同步和异步问题,并且有很多解决方法。 其中有“信号量机制”实现线程同步。 java的这个同步机制与操作系统类似。 结构是个复杂的问题,如果你感兴趣的话,可以试着找一下操作系统的书。
简单说明进程和线程的概念。
1 .过程:
进程是分配资源和独立执行的基本单元。 流程的定义很多,以下列举几个
过程是程序的执行
进程是可以与其他计算机同时运行的计算
流程可以定义为数据结构和可以在其上操作的程序
进程是指进程及其数据在处理程序上依次执行时发生的活动。
进程在一个数据集上运行的进程,是系统分配和调度资源的独立单元。
2 .线程
由于进程是资源的所有者,在进程的创建、撤销、切换过程中,系统需要支付很大的时空开销。 因此,系统中设置的进程数不能过多,进程切换的频率也不能过高,但这将限制并发性的提高。 于是引出了线程的概念
以线程为调度和分配的基本单位,以进程为资源拥有的基本单位,通过分离传统进程的两个属性,线程可以轻装运行,系统的并发性显著提高。
同一进程中可以有多个线程;
同一进程内线程的切换不会引起进程的切换;
当一个进程的线程切换到另一个进程的线程时,进程就会切换
3.JSP/servlet
我们常用的JSP/erv let J2ee的体系结构正是建立在java多线程的机制之上。 JSP/servlet容器自动使用线程池等技术来支持系统行为。 因此,JSP servlet的本质是线程技术,它在运行时编译并运行在servlet中,如下图所示。
当客户端向服务器发出请求时,servlet容器将分配一个处理该请求的线程。 线程的内容是JSP/servlet APP应用程序。
这部分的内容与本主体无关,顺便说一下。
4 .线程池
首先说明线程池。
创建、销毁、切换和运行线程需要耗费系统资源。 如果系统访问过多,在资源完全消耗之前,服务器中的线程过多,会对APP应用系统的正常运行造成致命的破坏。
为了在限制访问钉钉时活动线程的数量的同时,减少线程频繁创建和废弃带来的开销,提高对系统大量访问的处理性能和速度,需要事先创建一定数量的线程,以便调用方反复使用这就是“游泳池”技术。
线程的基本原理基于名为队列queue的数据结构,不断询问队列queue中是否有可执行的线程。 如果有,请立即运行线程;否则,请锁定并等待,直到新线程加入并解除锁定。 (该锁定机制是所谓的“信号量机制”。
线程池必须解决死锁、资源不足、并发错误、线程泄漏和请求过载等问题。 让我们举一个成熟的开源线程池的例子来说明线程池的原理。
pooledexecutorpool=newpooledexecutor (newboundedbuffer (20 ),100 );
pool.setminimumpoolsize(10 ); //最小线程数为10
poole.setkeepalivetime(-1; //线程一直在运行
上面的语句将最大线程数设置为100。 这样可以保护系统免受因访问次数增加而导致线程数无限增加的影响。 按如下方式使用线程池:
pool.execute (Java.lang.runnable自身的线程);
此语句实际上将“我的线程”放在一个队列中,另一个队列(先进先出FIFO )继续打开多个线程来读取此队列。 当队列中有空闲线程时,线程管理器将读取并分配线程以供执行。
公共语音执行(runnable command ) throwsInterruptedException{
for (; (//一直循环
同步(this ) {
if (! shutdown_ ) {//验证线程池是否未关闭
intsize=poolSize_; //当前线程池中的线程数
if (大小)
addthread(command;
返回
;}
//如果目前线程池中有超过或等于最小数目的线程
//分配一个存在的空闲线程来运行command,handOff是队列
if (handOff_.offer(command, 0)) {
return;
}
//如果不能分配已有的线程来运行command,那么创建一个新线程
if (size
addThread(command);
return;
}
}
}
//如果阻塞,则请求帮助
if (getBlockedExecutionHandler().bolckedAction(command)) {
return;
}
}
}
由上面的代码可见,PooledExecutor线程池的原理是,当执行execute加载一个应用系统的线程时,线程池内部首先检查当前线程数目是否达到设定的最小数目。如果没有达到,启动新线程运行;如果达到了,那么检查有无空闲线程可用;如果没有空闲的,则创建新线程,直到达到最大数目。
使用线程池的好处是:首先是循环使用,一经创建后,空闲的线程可以被反复使用,提高了运行效率;其次有最大数目的限制,保证了系统的安全性。
5.连接池
终于轮到连接池了,通过上面的介绍,我们对线程及线程池都有个一个大致的了解。
在正常情况下,直接使用JDBC调用数据库可以满足一个小型系统的要求,但是当系统规模比较大的情况下,就会出现数据库的访问量迅速提升而令服务器不堪重负的现象,因而为了解决这一性能问题,常常会使用数据库连接池作为一个缓存的方式解决。
连接池类似上面介绍的线程池。
每次数据库连接的建立都需要花费一定的时空费用,而使用连接池,可以事先建立连接。当应用程序需要开始使用时,就从连接池中获取一个连接使用,应用程序使用完毕,通过close()方法将连接归还连接池。讲到这里,我门就不必在担心close()方法会不会影响性能了,完全可以放心大胆的使用。因为,它实际上并没有关闭连接,而是将连接归还连接池,供下次使用。
当并发增加是,连接池会不断的自动创建新的连接满足调用,直到达到连接池的最大数目;当连接池连接减少甚至没有时,连接池自动关闭一些连接,保持最小数目。
因此连接池的使用节省了连接建立时间,消除了数据库频繁连接带来的开销和瓶颈。
小提示:不知道大家有没有注意到配置websphere时有关于连接池最大最小数目的配置。呵呵,道理就在这。
那么,我们经常面对的连接未关闭的问题导致的系统速度很慢的问题就很容易说明了,就是因为线程池已经达到了最大数目,没有可用的了。所以,其他操作只有等待的份,等待那些应用用完了,被垃圾回收了,才能释放出可用的连接。