【进阶之路】和南橘一块儿探索链接池(一)

1、链接池的定义

什么叫链接池?顾名思义,链接池就是将应用所需的链接对象放在池中,每次访问时从池中获取,使用完毕再放回池中,以达到链接复用的目的。链接池和线程池很像,都是为了减小链接对象在建立、销毁链接过程当中没必要要消耗的资源java

你们接触最多的链接池、大概是数据库链接或者tomcat链接池,C3P0、DBCP、Tomcat Jdbc Pool、BoneCP、Druid等。这些链接池的目的都很是的纯粹,即在服务启动的时候,预先生成若干条链接,每当有请求过来,就从中取出一个,执行操做,执行完成后再放回,从而避免反复的创建和销毁链接,以提高性能mysql

链接池性能对比sql

实际在微服务中,链接池是很是重要的组件,由于服务间须要创建链接通讯,经过链接池能够极大地提升服务间的通讯性能。数据库

通常链接池的实现,图片来自拉钩教育

所以,咱们只要创建多条链接,用一个数组维护多条链接就好了;若是使用一条链接,那么从数组里拿出这条链接,使用完再放入数组便可。当数组为空时,只要创建新的链接就能够了。后端

2、自定义链接池

具体的实现能够参考我下文实现的代码。这个链接池拥有了几个基本数据。数组

  • maxIdleConns 最大空闲链接数,这个值至关于线程池里的核心线程数、与线程池不同的是,配置了最大空闲数后,链接池的链接将会长期保持。这个值的设置颇有讲究,须要结合后端服务的链接承载能力设置tomcat

  • currentCount 当前使用数目,相似于核心线程数到最短线程数以前的这个值。微信

  • maxIdCount 最大链接数,表明着链接池的上限。多线程

  • ttls 链接的过时时间,这个时间线程池中也有,若是链接都为空闲链接,则不会进行过时处理。并发

public class MyPool {

    // 最大链接数 
    private int maxIdCount;
    //记录当前使用 的链接数目
    private int currentCount ;
    //初始化线程数、最大空闲链接数
    private int maxIdleConns;
	// 多久后链接会断开,不少链接池会在必定时间后断开链接,而后将新鲜的链接放入链接池
    private int ttls;

    //咱们用LinkedList来定义一个链接池
    private LinkedList<Connections> connectionPool;

    public MyPool(int maxIdleConns, int currentCount,int maxIdCount,int ttls) {
        this.maxIdleConns = maxIdleConns;
        this.currentCount = currentCount;
        this.maxIdCount =maxIdCount;
        this.ttls=ttls;
        this.connectionPool = new LinkedList<Connections>();

        for(int i=0;i<maxIdleConns;i++){
            connectionPool.add(createConnection());
        }
    }
    /**
     * 创建一个连接
     * @return  Connection
     */
    public    Connections createConnection(){
        try {

            Class.forName("com.mysql.jdbc.Driver");
            return new Connections(DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "root"), DateUtil.getCurrTime());
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 先判断链接池中是否有链接,若是有直接使用,若是没有链接,
     * 则先判断当前的链接是否达到最大链接数,达到的话 抛出异常,没有达到最大链接 则建立链接
     * @return
     */
    public Connections getConnection(){
        //1.判断,池中如有链接直接使用
        if(connectionPool.size()>0){
            //把这个连接移出集合并返回当前链接对象。
            currentCount++;
            return connectionPool.removeFirst();

        }
        //若是池中没有链接并且没有达到最大链接数目;则建立链接
        if(currentCount>=maxIdleConns && currentCount<maxIdCount){
            currentCount++;
            //建立一个新的链接
            return createConnection();
        }
        //判断是否达到最大链接数,达到则抛出异常
        System.out.println();
        throw new RuntimeException("当前链接已经达到最大链接数!");
    }


    /**
     * 把链接放回链接池(集合)中。若是池中链接数小初始化链接数目就放回池中,其余则关闭链接。
     * @param conn
     */
    public void releaseConnection(Connections conn){
        //判断池中的数目若是小于初始化链接就放回链接池中
        //判断链接池中的剩余数目是否<链接池初始化数目   若是为真 则放回链接池
        if(currentCount<=maxIdCount){
            //放回链接池
            connectionPool.addLast(conn);
            //当前链接-1
            currentCount--;

        }else{
            //关闭链接
            try {
                conn.connection.close();
                currentCount--;
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 清除所有超时链接
     * 初始化线程数无需释放
     * @param connectionPool
     */
    public void release(LinkedList<Connections> connectionPool){
        if (connectionPool.size()<1||currentCount==0){
            return;
        }
        if ( ttls<(DateUtil.getCurrTime()-connectionPool.getFirst().getTtl())){
            Connections conn = connectionPool.getFirst();
            //当前链接-1
            currentCount--;
            connectionPool.removeFirst();
            //关闭链接
            try {
                conn.connection.close();
                currentCount--;
            } catch (SQLException e) {
                e.printStackTrace();
            }
            release(connectionPool);
        }
    }
}

3、链接池须要的问题

一、并发问题

上面的代码只是我简单实现了一下链接池,可是为了使链接管理服务具备最大的通用性,必须考虑多线程环境,即并发问题。在java中,有各类锁的机制可以解决链接池的并发问题。

二、链接池大小的设置

若是设置得太大,假如设置 1000,始发集群有 100 台机器,那么就会创建 10w 的持久链接,这对后端服务的压力可想而知。但也不能设置得过小。

若是链接池满了,就会创建新的链接,不断创建的新链接会耗光后端服务的资源。

新创建的链接在用完以后,有两种选择——链接池有余量的状况会放入链接池,反之会直接丢弃,这种状况在瞬间很容易出现,链接池持续瞬间被空闲链接占满(最大空闲链接数的叫法也由此得来),致使新链接没法放回链接池,进而丢弃,这样就会造成创建链接—用完丢弃的恶性循环,链接池的做用也就消失了。对于HTTP请求的链接池来讲,全部的链接都退化成了短链接。

实际上链接并无长短之分,只是取决于传输完数据后是否断开。那么为何会有长短链接的叫法呢?这是由于 HTTP 协议多用于 Web 中,Web 的交互方式可能是一来一回的模式,这样的应用场景下,不须要服务端推数据,因此创建链接后当即释放也是彻底能够的。

三、链接池的分配与释放

链接池的分配与释放,对系统的性能有很大的影响。合理的分配与释放,能够提升链接的复用度,从而下降创建新链接的开销,同时还能够加快用户的访问速度。
咱们这个链接池是使用LinkedList来实现的,主要的目的是考虑到过时时间。在链表中,前面链接的持续时间必定高于后面的链接,也能够减小链接的轮循时间。

你们好,我是练习java两年半时间的南橘,下面是个人微信,须要以前的导图或者想互相交流经验的小伙伴能够一块儿互相交流哦。

相关文章
相关标签/搜索