Druid连接池获取连接源码浅析

JDBC的API设计中有一个DriverManager类,它提供了一个静态方法getConnection()该方法用于与数据库建立一个连接,返回一个Connection实例。

而在JDBC2.0版本的API中提供了一个新的接口:javax.sql.DataSource,该接口也提供抽象方法getConnection(),Druid基于该接口做了连接池的实现,即:DruidDataSource实现类。

DataSource接口的javaDoc: http://tool.oschina.net/uploads/apidocs/jdk-zh/javax/sql/DataSource.html

简要流程

以下内容将关注DruidDataSource的getConnection()接口实现,我们可以先找到javax.sql.DataSource接口:

向下找到DruidDataSource实现类

和getConnection()的实现

我们看到getConnection()调用了一个内部方法,传入maxWait入参(最大等待时间),进入内部方法

getConnection()方法主要做了两步,1)连接池初始化操作;2)获取连接;

我们进入init方法看看初始化,初始化方法很长,这里关注以下两块内容

1、同步初始化连接

我们看到首先基于maxActive这里配置创建了一个Connection的数组,然后根据initialSize这个配置初始化了对应的Connection实例并在数组里存放。(这点和ThreadPoolExecutor线程池不一样,线程池是一个一个创建,连接池是首次直接全部创建,后续不再调用init方法);

2、线程生产者,在同步初始化连接的情况下将启动一个Connection的创建线程作为生产者。

我们打开生产者线程实现的run方法,代码主要是以下两块

第一部分,等待创建连接的信号

第二部分,创建完成的非空信号通知(通知等待创建完成的线程去消费Connection)

我们可以看到,在初始化过程中创建了相应数量的Connection连接,再启动了一个Connection生产者线程等待消费者通知去创建Connection连接。

init方法结束以后,我们再进入getConnectionDirect方法看看怎么获取连接

该方法又调用了一个内部方法,如果失败有重试机制,再进入内部方法

getConnectionInternal方法很长,我们忽略次要部分,关注以下内容

如果设置了等待时间则调用pollLast阻塞等待,如果没有则调用takeLast无限阻塞。这里我们点开pollLast()方法看看

首先,如果没有Connection就会发送空的信号给我们上面的生产者线程

然后就阻塞等待生产者的通知

等待结束以后再次判断是否为空(这里是典型的条件谓词的二次校验做法),还为空则再循环一遍。

如果有可用连接将获取并返回

原理实现

 DruidDataSource的原理看起来比较简单,就是基于ReentrantLock和Condition的条件队列实现了生产者和消费者模式。生产者由一个线程处理(同步模式),消费者多线程。

下面我们看一个伪代码:

首先定义一把锁和两个信号,一个是空信号,一个是非空信号

生产者,先进行条件判断,如果非空则进入等待,如果空,则创建

消费者

伪代码中注意一点,wait方法在之前要做条件谓词判断,之后也要做条件谓词判断这样才不会导致信号丢失。

 

转载于:https://www.cnblogs.com/lay2017/p/10977300.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值