【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. }  

经过链接池的管理,实现了数据库链接的共享,不须要每一次都从新建立链接,节省了数据库从新建立的开销,提高了系统的性能!

相关文章
相关标签/搜索