09 November 2019

为啥快

  • 只干必要的事情
  • 消除线程竞争
  • 减少调用消耗
  • 业务层面

只干必要的事情

只实现了数据源的基本功能,没有什么花哨的功能。

  • 代理了Connection Statement CallableStatement PreparedStatement ResultSet实例,没有提供什么拦截器之类的额外功能。
  • 指标监控比较简单,包括totalConnections idleConnections activeConnections pendingThreads

消除线程竞争

参见ConcurrentBag的实现。

使用ThreadLocal将连接与线程绑定,消除了大部分线程竞争的情况。

减少调用消耗

使用静态方法代替实例方法减少调用消耗。这部分消耗主要是invokestaticinvokevirtual字节码使用上有差别造成的。

不过这里不明白为什么要动态生成字节码而不是直接编码。

业务考虑

在关闭Statement时,需要在Connection中取消与该Statement的关联。那么如何快速找到Connection中的Statement呢?

使用Map是一个方法,不过空间上略有浪费。另一个方法是使用List,但需要遍历,不过对于一般业务来说,数量不太多,遍历倒也还好。不过使用JDK自带的List实现来说,在数据源使用这个业务场景下,remove方法的性能不太好,因为remove方法是从前向后遍历的,而实际的业务场景中,大部分情况是先关闭最后一个即可,即FILO模式。虽然可以使用LinkedList来规避问题,但LinkedList的空间局部性不好。Hikari的解决方案是自己实现了List,即FastList,对于remove方法的实现就是从后向前遍历,力求尽快退出循环,同时使用 相同代替 相等作为判断条件,提高效率。

与Tomcat-JDBC对比

  • tomcat-jdbc使用了buzyidle两个列表来保存连接,并发场景下加锁/解锁操作较多
  • tomcat-jdbc支持interceptor机制,功能上更强,当然耗时也会更多

Resources