• 【Java】连接池、线程池 各种池【转+整理】与享元模式。


    谈谈连接池、线程池技术原理

     
     
      做互联网研发,最早接触使用jdbc技术,为了数据库连接能够复用,会用到c3p0、dbcp等数据库连接池。应该是研发人员最早接触的数据库连接池,再到httpclient http连接池,再到微服务netty连接池redis客户端连接池,以及jdk中线程池技术。

       这么多数据库、http、netty连接池,jdk线程池,本质上都是连接池技术,连接池技术核心连接或者说创建的资源复用

       连接池技术核心:通过减少连接创建、关闭来提升性能。用于用户后续使用,好处是后续使用不用在创建连接以及线程,因为这些都需要相关很多文件、连接资源、操作系统内核资源支持来完成构建,会消耗大量资源,并且创建、关闭会消耗应用程序大量性能。

       网络连接本身会消耗大量内核资源,在linux系统下,网络连接创建本身tcp/ip协议栈在内核里面,连接创建关闭会消耗大量文件句柄(linux中万物皆文件,一种厉害抽象手段)系统资源。当下更多是应用tcp技术完成网络传输,反复打开关闭,需要操作系统维护大量tcp协议栈状态。

       连接池本质上是构建一个容器,容器来存储创建好的线程、http连接、数据库连接、netty连接等。对于使用方相当于黑盒,按照接口进行使用就可以了。各个连接池构建、使用管理详细过程大概分成以下三部分。

       第一部分:首先初始化连接池,根据设置相应参数,连接池大小、核心线程数、核心连接数等参数,初始化创建数据库、http、netty连接以及jdk线程。

       第二部分:连接池使用,前边初始化好的连接池、线程池,直接从连接池、线程中取出资源即可进行使用,使用完后要记得交还连接池、线程池,通过池容器来对资源进行管理。

       第三部分:对于连接池维护,连接池、线程池来维护连接、线程状态,不可用连接、线程进行销毁,正在使用连接、线程进行状态标注,连接、线程不够后并且少于设置最大连接、线程数,要进行新连接、线程创建。

       通过上边可以了解到各种连接池技术以及线程池原理或者说套路,理解原理才能不被纷繁复杂表象掩盖。

       下面谈谈构建自己连接池,其实理解了连接池、线程原理,可以使用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. }  

    通过连接池的管理,实现了数据库连接的共享,不需要每一次都重新创建连接,节省了数据库重新创建的开销,提升了系统的性能!

  • 相关阅读:
    给文章生成二维码
    用HTML5 Canvas做一个画图板
    失败多少次不要紧,人们只会记住你成功的那一次
    关于读大学的意义
    卸载Anaconda
    Anaconda基本命令
    plt.imshow()
    matplotlib不显示图片
    在Anaconda环境下使用Jupyter Notebook
    join()
  • 原文地址:https://www.cnblogs.com/CESC4/p/8041198.html
Copyright © 2020-2023  润新知