【Java】鏈接池、線程池 各類池【轉+整理】與享元模式。

談談鏈接池、線程池技術原理

 
 
  作互聯網研發,最先接觸使用jdbc技術,爲了數據庫鏈接可以複用,會用到c3p0、dbcp等數據庫鏈接池。應該是研發人員最先接觸的數據庫鏈接池,再到httpclient http鏈接池,再到微服務netty鏈接池redis客戶端鏈接池,以及jdk中線程池技術。

   這麼多數據庫、http、netty鏈接池,jdk線程池,本質上都是鏈接池技術,鏈接池技術核心鏈接或者說建立的資源複用java

   鏈接池技術核心:經過減小鏈接建立、關閉來提高性能。用於用戶後續使用,好處是後續使用不用在建立鏈接以及線程,由於這些都須要相關不少文件、鏈接資源、操做系統內核資源支持來完成構建,會消耗大量資源,而且建立、關閉會消耗應用程序大量性能。mysql

   網絡鏈接自己會消耗大量內核資源,在linux系統下,網絡鏈接建立自己tcp/ip協議棧在內核裏面,鏈接建立關閉會消耗大量文件句柄(linux中萬物皆文件,一種厲害抽象手段)系統資源。當下更可能是應用tcp技術完成網絡傳輸,反覆打開關閉,須要操做系統維護大量tcp協議棧狀態。linux

   鏈接池本質上是構建一個容器,容器來存儲建立好的線程、http鏈接、數據庫鏈接、netty鏈接等。對於使用方至關於黑盒,按照接口進行使用就能夠了。各個鏈接池構建、使用管理詳細過程大概分紅如下三部分。redis

   第一部分:首先初始化鏈接池,根據設置相應參數,鏈接池大小、核心線程數、核心鏈接數等參數,初始化建立數據庫、http、netty鏈接以及jdk線程。sql

   第二部分:鏈接池使用,前邊初始化好的鏈接池、線程池,直接從鏈接池、線程中取出資源便可進行使用,使用完後要記得交還鏈接池、線程池,經過池容器來對資源進行管理。數據庫

   第三部分:對於鏈接池維護,鏈接池、線程池來維護鏈接、線程狀態,不可用鏈接、線程進行銷燬,正在使用鏈接、線程進行狀態標註,鏈接、線程不夠後而且少於設置最大鏈接、線程數,要進行新鏈接、線程建立。安全

   經過上邊能夠了解到各類鏈接池技術以及線程池原理或者說套路,理解原理才能不被紛繁複雜表象掩蓋。微信

   下面談談構建本身鏈接池,其實理解了鏈接池、線程原理,可使用ArrayList來構建本身鏈接池、線程池。初始化時建立配置鏈接數、線程,存儲在ArrayList容器中,使用時從ArrayList從取出鏈接、線程進行使用,執行完任務後,提交回ArrayList容器。前提條件是單線程,在多線程狀態下要用線程安全容器網絡

   前邊根據原理介紹了一個簡單鏈接池、線程池怎樣構建,實際工業級別線程池還要考慮到鏈接狀態,短鏈接重連,線程池維護管理高效,線程池穩定等多個因素。多線程

   須要用到鏈接池而又沒有相關開源產品可用時,java鏈接池可使用common-pool2來構建,好比google開源gRPC技術,自己是高性能跨平臺技術,但目前做爲微服務使用,沒有鏈接池、負載均衡等相應配套,這時能夠根據須要本身基於Java容器構建本身鏈接池。也能夠利用common-pool2構建鏈接池來提高應用性能,以及保持高可用。common-pool2自己不只僅能夠構建鏈接池使用,還能夠用來構建對象池。

   鏈接池還有一個反作用就是實現了高可用,在微服務場景下一個鏈接不可用,那麼再從netty鏈接池中取出一個進行使用,避免了鏈接不可用問題。

   掌握原理從比較全面掌握各類池技術,避免數據庫鏈接池,再到httpclient http鏈接池,再到微服務netty鏈接池,redis客戶端鏈接池,以及jdk中線程池,對象池各類各樣池技術,使咱們眼花繚亂,花費過多時間,掌握原理機制以不變應萬變

   推廣一下這個方法,其餘技術也是相似,深刻掌握其原理,就能夠明白其餘相似技術類似原理,避免疲於應對各類新技術。但每一種架構設計與實現又與領域有着關係,也不可講原理不顧實際狀況擴展。理論與架構設計、源碼學習相結合纔是最好的,但願有幫助。

 


 享元模式的主要目的是實現對象的共享,即共享池,當系統中對象多的時候能夠減小內存的開銷,一般與工廠模式一塊兒使用。

FlyWeightFactory負責建立和管理享元單元,當一個客戶端請求時,工廠須要檢查當前對象池中是否有符合條件的對象,若是有,就返回已經存在的對象,若是沒有,則建立一個新對象,FlyWeight是超類。

一提到共享池,咱們很容易聯想到Java裏面的JDBC鏈接池,想一想每一個鏈接的特色,咱們不難總結出:適用於做共享的一些個對象,他們有一些共有的屬性,就拿數據庫鏈接池來講,urldriverClassNameusernamepassworddbname這些屬性對於每一個鏈接來講都是同樣的,因此就適合用享元模式來處理,建一個工廠類,將上述相似屬性做爲內部數據其它的做爲外部數據,在方法調用時,當作參數傳進來,這樣就節省了空間,減小了實例的數量。

看個例子:

 

看下數據庫鏈接池的代碼:

[java] view plaincopy

  1. public class ConnectionPool {  
  2.       
  3.     private Vector<Connection> pool;  
  4.       
  5.     /*公有屬性*/  
  6.     private String url = "jdbc:mysql://localhost:3306/test";  
  7.     private String username = "root";  
  8.     private String password = "root";  
  9.     private String driverClassName = "com.mysql.jdbc.Driver";  
  10.   
  11.     private int poolSize = 100;  
  12.     private static ConnectionPool instance = null;  
  13.     Connection conn = null;  
  14.   
  15.     /*構造方法,作一些初始化工做*/  
  16.     private ConnectionPool() {  
  17.         pool = new Vector<Connection>(poolSize);  
  18.   
  19.         for (int i = 0; i < poolSize; i++) {  
  20.             try {  
  21.                 Class.forName(driverClassName);  
  22.                 conn = DriverManager.getConnection(url, username, password);  
  23.                 pool.add(conn);  
  24.             } catch (ClassNotFoundException e) {  
  25.                 e.printStackTrace();  
  26.             } catch (SQLException e) {  
  27.                 e.printStackTrace();  
  28.             }  
  29.         }  
  30.     }  
  31.   
  32.     /* 返回鏈接到鏈接池 */  
  33.     public synchronized void release() {  
  34.         pool.add(conn);  
  35.     }  
  36.   
  37.     /* 返回鏈接池中的一個數據庫鏈接 */  
  38.     public synchronized Connection getConnection() {  
  39.         if (pool.size() > 0) {  
  40.             Connection conn = pool.get(0);  
  41.             pool.remove(conn);  
  42.             return conn;  
  43.         } else {  
  44.             return null;  
  45.         }  
  46.     }  
  47. }  

經過鏈接池的管理,實現了數據庫鏈接的共享,不須要每一次都從新建立鏈接,節省了數據庫從新建立的開銷,提高了系統的性能!

相關文章
相關標籤/搜索