数据库连接池-连接的关闭内幕
???????下面我就想就上面的問題談談我的一點淺見,請大家批評指正。
???????大家都知道java語言是一種語言級的多線程機制的面向對象語言。比如說,java的基類object,它就有一些諸如wati(),notify(),notifyall()等線程控制的方法。如果大家學習過操作系統的化,我想應該知道線程存在同步和異步的問題,解決的方法很多,其中就有“信號量機制”實現線程的同步,java的這種同步機制與操作系統大同小異。同步機制是一個比較復雜的問題,如果感興趣可以找一本操作系統的書看看。
???????下面簡單介紹一些進程和線程的概念:
1.?????????進程:
???????進程是資源分配和獨立運行的基本單位。進程的定義很多,下面列舉一些
??????????進程是程序的一次執行;
??????????進程是可以和別的計算機并發執行的計算;
??????????進程可定義為一個數據結構及能在其上進行操作的一個程序
??????????進程是一個程序及其數據在處理機上順序執行時發生的活動;
??????????進程時程序在一個數據集合上的運行過程,時系統進行資源分配和調度的一個獨立單位。
2.?????????線程
由于進程是一個資源擁有者,因而在進程的創建、撤消和切換過程中,系統必須為之付出較大的時空開銷。也正因為如此,在系統中所設置的進程數目不宜過多,進程切換的頻率也不宜過高,但這也就限制了并發程度的進一步提高。因此便引出了線程的概念
把線程作為調度和分派的基本單位,而把進程作為資源擁有的基本單位,使傳統進程的兩個屬性分開,線程便能輕裝運行,從而顯著提高系統的并發程度。
??????????在同一個進程內可以有多個線程;
??????????同一個進程內的線程切換不會引起進程切換;
??????????一個進程的線程切換到另一個進程的線程時會引起進程切換
3.?????????JSP/SERVLET
而我們常用的jsp/ervlet這種j2ee的體系結構正是建立在java的多線程機制之上的。JSP/SERVLET容器會自動使用線程池等技術來支持系統的運行。因此,JSP/SERVLET的實質是一種線程技術,JSP會在運行時被編譯成servlet來運行,如圖所示:
???????當客戶端向服務器發出一個請求時,servlet容器會分配一個線程專門處理這個請求,線程內容就是JSP/servlet應用程序。
???????這部分內容與本主體無關,只是順便說說。
4.?????????線程池
???????首先介紹一下線程池:
???????線程的創建和銷毀,以及切換,執行都是要耗費系統資源的。當系統訪問量比較大的時候,服務器內就會創建太多的線程,直至資源完全消耗,這對于應用系統的正常運行是有致命傷害的。
???????為了能夠在訪問尖峰時限制活動線程的數量,同時減少線程頻繁創建和銷毀帶來的系統開銷,提高系統的大訪問量的處理性能和速度,需要事先創建一定數量的線程供調用者循環反復使用,這就是“池”技術。
???????線程的基本原理是基于隊列queue這種數據結構的,通過不斷查詢隊列queue是否有可以運行的線程。如果有,就立即運行線程,沒有,則鎖定等待,直到有新的線程加入被解鎖。(這種鎖定機制,就是所謂的“信號量機制”)。
???????一種線程池必須解決如下的問題:死鎖、資源不足、并發錯誤、線程泄漏和請求過載。下面我們具體舉一個成熟的開源線程池的例子來說明線程池的原理:
????PooledExecutor?pool=new?PooledExecutor(new?BoundedBuffer(20),100);
????pool.setMinimumPoolSize(10);//最小線程數為10
????poole.setKeepAliveTime(-1);//線程一直運行
????上面的語句設置了線程的最大數目為100,這樣,就可以保護系統不會因為訪問量增加導致線程數目的無限增加。使用該線程池如下:
???????pool.execute(java.lang.Runnable?自己的線程);
???????這一句實際上是將“自己的線程”加入一個隊列中,而隊列(先進先出FIFO)另一段正開啟多個線程不斷讀取這個隊列,一旦隊列中有空閑的線程,線程管理器就將讀取并分配線程來運行它。
? ? ??
????public?void?execute(Runnable?command)?throws?InterruptedException?{
???????for?(;;)?{?//一直循環
???????????synchronized?(this)?{
??????????????if?(!shutdown_)?{?//確保線程池沒有關閉
??????????????????int?size?=?poolSize_;?//當前線程池中線程的數目
??????????????????if?(size?<?minimumPoolSize_)?{?//如果當前線程數目少于線程池最小數目
?????????????????????addThread(command);
?????????????????????return;
??????????????????}
??????????????????//如果目前線程池中有超過或等于最小數目的線程
??????????????????//分配一個存在的空閑線程來運行command,handOff是隊列
??????????????????if?(handOff_.offer(command,?0))?{
?????????????????????return;
??????????????????}
??????????????????//如果不能分配已有的線程來運行command,那么創建一個新線程
??????????????????if?(size?<?maximumPoolSize_)?{
?????????????????????addThread(command);
?????????????????????return;
??????????????????}
??????????????}
???????????}
???????????//如果阻塞,則請求幫助
???????????if?(getBlockedExecutionHandler().bolckedAction(command))?{
??????????????return;
???????????}
???????}
????}
???????由上面的代碼可見,PooledExecutor線程池的原理是,當執行execute加載一個應用系統的線程時,線程池內部首先檢查當前線程數目是否達到設定的最小數目。如果沒有達到,啟動新線程運行;如果達到了,那么檢查有無空閑線程可用;如果沒有空閑的,則創建新線程,直到達到最大數目。
???????使用線程池的好處是:首先是循環使用,一經創建后,空閑的線程可以被反復使用,提高了運行效率;其次有最大數目的限制,保證了系統的安全性。
5.?????????連接池
終于輪到連接池了,通過上面的介紹,我們對線程及線程池都有個一個大致的了解。
在正常情況下,直接使用JDBC調用數據庫可以滿足一個小型系統的要求,但是當系統規模比較大的情況下,就會出現數據庫的訪問量迅速提升而令服務器不堪重負的現象,因而為了解決這一性能問題,常常會使用數據庫連接池作為一個緩存的方式解決。
連接池類似上面介紹的線程池。
每次數據庫連接的建立都需要花費一定的時空費用,而使用連接池,可以事先建立連接。當應用程序需要開始使用時,就從連接池中獲取一個連接使用,應用程序使用完畢,通過close()方法將連接歸還連接池。講到這里,我門就不必在擔心close()方法會不會影響性能了,完全可以放心大膽的使用。因為,它實際上并沒有關閉連接,而是將連接歸還連接池,供下次使用。
當并發增加是,連接池會不斷的自動創建新的連接滿足調用,直到達到連接池的最大數目;當連接池連接減少甚至沒有時,連接池自動關閉一些連接,保持最小數目。
因此連接池的使用節省了連接建立時間,消除了數據庫頻繁連接帶來的開銷和瓶頸。
小提示:不知道大家有沒有注意到配置websphere時有關于連接池最大最小數目的配置。呵呵,道理就在這。
那么,我們經常面對的連接未關閉的問題導致的系統速度很慢的問題就很容易說明了,就是因為線程池已經達到了最大數目,沒有可用的了。所以,其他操作只有等待的份,等待那些應用用完了,被垃圾回收了,才能釋放出可用的連接。?
總結
以上是生活随笔為你收集整理的数据库连接池-连接的关闭内幕的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: wpf资源嵌套,一个资源引用另外一个资源
- 下一篇: 【web开发学习笔记】Structs2
