Druid连接池管理连接池中的空闲连接驱逐流程

ops/2024/12/30 21:10:57/

Druid连接池中的驱逐空闲线程流程主要涉及以下几个步骤:

1. 创建和启动驱逐线程

  • createAndStartDestroyThread 方法:此方法负责创建和启动负责驱逐空闲连接的线程。如果提供了 destroyScheduler(一个调度器),则使用该调度器定期执行 DestroyTask 任务;如果没有提供,则创建一个 DestroyConnectionThread 线程并启动。

2. 驱逐线程的运行逻辑 (DestroyConnectionThread)

  • run 方法:驱逐线程的主要逻辑在这里实现。
    • 初始时,调用 initedLatch.countDown() 表示线程已初始化。
    • 进入无限循环,根据 timeBetweenEvictionRunsMillis 的值决定休眠时间,如果没有设置则默认休眠1000毫秒。
    • 检查线程是否被中断,如果是,则退出循环。
    • 调用 destoryTask.run() 执行实际的驱逐任务。

3. 驱逐任务的执行逻辑 (DestroyTask)

  • run 方法:执行驱逐任务。
    • 调用 shrink(true) 方法检查并驱逐空闲连接。
    • 如果启用了移除被遗弃的连接,则调用 removeAbandoned() 方法处理。

4. 执行 shrink 方法

  • 参数shrink 方法接受两个参数,checkTime 和 keepAlive,分别用于控制是否检查连接的空闲时间以及是否执行连接的保活检测。
    • 锁定:首先尝试获取锁,如果被中断则返回。
    • 初始化变量:初始化一些变量,如 evictCount(待驱逐连接数)和 keepAliveCount(保活连接数)。
    • 遍历连接:遍历连接池中的所有连接,根据 checkTime 参数决定是否检查连接的空闲时间。
      • 物理超时:如果连接的物理超时时间超过 phyTimeoutMillis,则将连接添加到待驱逐列表。
      • 空闲时间检查:如果连接的空闲时间超过 minEvictableIdleTimeMillis 或小于 maxEvictableIdleTimeMillis,则将连接添加到待驱逐列表。
      • 保活检查:如果 keepAlive 为 true 且连接的空闲时间超过 keepAliveBetweenTimeMillis,则将连接添加到保活列表。
    • 更新连接池:如果待驱逐或保活列表中有连接,则更新连接池数组,移除待驱逐的连接,并补充新的连接以保持连接池的大小。
    • 释放锁:最后释放锁。

5. 驱逐空闲连接

  • 执行 evictConnections:遍历待驱逐连接列表,关闭连接并更新统计信息。

6. 执行保活检查

  • 执行 keepAliveConnections:遍历保活连接列表,对每个连接执行保活检查。
    • 验证连接:尝试验证连接的有效性,如果连接无效,则标记为丢弃。
    • 重新放入连接池:如果连接有效,则尝试将其重新放回连接池中。
    • 丢弃连接:如果连接被标记为丢弃,则关闭连接并更新统计信息。

7. 补充连接池

  • needFill 检查:如果连接池中的连接数少于 minIdle,则尝试补充新的连接。

通过以上步骤,Druid连接池能够有效地管理空闲连接,确保连接池的健康和高效运行。

##源码

public void shrink(boolean checkTime, boolean keepAlive) {try {lock.lockInterruptibly();} catch (InterruptedException e) {return;}boolean needFill = false;int evictCount = 0;int keepAliveCount = 0;int fatalErrorIncrement = fatalErrorCount - fatalErrorCountLastShrink;fatalErrorCountLastShrink = fatalErrorCount;try {if (!inited) {return;}final int checkCount = poolingCount - minIdle;final long currentTimeMillis = System.currentTimeMillis();for (int i = 0; i < poolingCount; ++i) {DruidConnectionHolder connection = connections[i];if ((onFatalError || fatalErrorIncrement > 0) && (lastFatalErrorTimeMillis > connection.connectTimeMillis))  {keepAliveConnections[keepAliveCount++] = connection;continue;}if (checkTime) {if (phyTimeoutMillis > 0) {long phyConnectTimeMillis = currentTimeMillis - connection.connectTimeMillis;if (phyConnectTimeMillis > phyTimeoutMillis) {evictConnections[evictCount++] = connection;continue;}}long idleMillis = currentTimeMillis - connection.lastActiveTimeMillis;if (idleMillis < minEvictableIdleTimeMillis&& idleMillis < keepAliveBetweenTimeMillis) {break;}if (idleMillis >= minEvictableIdleTimeMillis) {if (checkTime && i < checkCount) {evictConnections[evictCount++] = connection;continue;} else if (idleMillis > maxEvictableIdleTimeMillis) {evictConnections[evictCount++] = connection;continue;}}if (keepAlive && idleMillis >= keepAliveBetweenTimeMillis) {keepAliveConnections[keepAliveCount++] = connection;}} else {if (i < checkCount) {evictConnections[evictCount++] = connection;} else {break;}}}int removeCount = evictCount + keepAliveCount;if (removeCount > 0) {System.arraycopy(connections, removeCount, connections, 0, poolingCount - removeCount);Arrays.fill(connections, poolingCount - removeCount, poolingCount, null);poolingCount -= removeCount;}keepAliveCheckCount += keepAliveCount;if (keepAlive && poolingCount + activeCount < minIdle) {needFill = true;}} finally {lock.unlock();}if (evictCount > 0) {for (int i = 0; i < evictCount; ++i) {DruidConnectionHolder item = evictConnections[i];Connection connection = item.getConnection();JdbcUtils.close(connection);destroyCountUpdater.incrementAndGet(this);}Arrays.fill(evictConnections, null);}if (keepAliveCount > 0) {// keep orderfor (int i = keepAliveCount - 1; i >= 0; --i) {DruidConnectionHolder holer = keepAliveConnections[i];Connection connection = holer.getConnection();holer.incrementKeepAliveCheckCount();boolean validate = false;try {this.validateConnection(connection);validate = true;} catch (Throwable error) {if (LOG.isDebugEnabled()) {LOG.debug("keepAliveErr", error);}// skip}boolean discard = !validate;if (validate) {holer.lastKeepTimeMillis = System.currentTimeMillis();boolean putOk = put(holer, 0L);if (!putOk) {discard = true;}}if (discard) {try {connection.close();} catch (Exception e) {// skip}lock.lock();try {discardCount++;if (activeCount + poolingCount <= minIdle) {emptySignal();}} finally {lock.unlock();}}}this.getDataSourceStat().addKeepAliveCheckCount(keepAliveCount);Arrays.fill(keepAliveConnections, null);}if (needFill) {lock.lock();try {int fillCount = minIdle - (activeCount + poolingCount + createTaskCount);for (int i = 0; i < fillCount; ++i) {emptySignal();}} finally {lock.unlock();}} else if (onFatalError || fatalErrorIncrement > 0) {lock.lock();try {emptySignal();} finally {lock.unlock();}}}public class DestroyConnectionThread extends Thread {public DestroyConnectionThread(String name){super(name);this.setDaemon(true);}public void run() {initedLatch.countDown();for (;;) {// 从前面开始删除try {if (closed) {break;}if (timeBetweenEvictionRunsMillis > 0) {Thread.sleep(timeBetweenEvictionRunsMillis);} else {Thread.sleep(1000); //}if (Thread.interrupted()) {break;}destoryTask.run();} catch (InterruptedException e) {break;}}}}public class DestroyTask implements Runnable {@Overridepublic void run() {shrink(true);if (isRemoveAbandoned()) {removeAbandoned();}}}public int removeAbandoned() {int removeCount = 0;long currrentNanos = System.nanoTime();List<DruidPooledConnection> abandonedList = new ArrayList<DruidPooledConnection>();synchronized (activeConnections) {Iterator<DruidPooledConnection> iter = activeConnections.keySet().iterator();for (; iter.hasNext();) {DruidPooledConnection pooledConnection = iter.next();if (pooledConnection.isRunning()) {continue;}long timeMillis = (currrentNanos - pooledConnection.getConnectedTimeNano()) / (1000 * 1000);if (timeMillis >= removeAbandonedTimeoutMillis) {iter.remove();pooledConnection.setTraceEnable(false);abandonedList.add(pooledConnection);}}}if (abandonedList.size() > 0) {for (DruidPooledConnection pooledConnection : abandonedList) {synchronized (pooledConnection) {if (pooledConnection.isDisable()) {continue;}}JdbcUtils.close(pooledConnection);pooledConnection.abandond();removeAbandonedCount++;removeCount++;if (isLogAbandoned()) {StringBuilder buf = new StringBuilder();buf.append("abandon connection, open stackTrace\n");StackTraceElement[] trace = pooledConnection.getConnectStackTrace();for (int i = 0; i < trace.length; i++) {buf.append("\tat ");buf.append(trace[i].toString());buf.append("\n");}LOG.error(buf.toString());}}}return removeCount;}protected void createAndStartDestroyThread() {destoryTask = new DestroyTask();if (destroyScheduler != null) {long period = timeBetweenEvictionRunsMillis;if (period <= 0) {period = 1000;}destroySchedulerFuture = destroyScheduler.scheduleAtFixedRate(destoryTask, period, period,TimeUnit.MILLISECONDS);initedLatch.countDown();return;}String threadName = "Druid-ConnectionPool-Destroy-" + System.identityHashCode(this);destroyConnectionThread = new DestroyConnectionThread(threadName);destroyConnectionThread.start();}


http://www.ppmy.cn/ops/145936.html

相关文章

info There appears to be trouble with your network connection. Retrying

这个错误信息表明你在使用包管理器安装项目依赖时遇到了网络连接问题。 可能的解决方法&#xff1a; 检查当前node.js版本是否过低。 建议使用当前长期支持版本 yarn的淘宝镜像&#xff1a;yarn的淘宝镜像-CSDN博客 nvm常用命令:NVM常用命令-CSDN博客 下载 | Node.js 中文…

如何在网页端使用 IDE 高效地阅读 GitHub 源码?

如何在网页端使用 IDE 高效地阅读 GitHub 源码&#xff1f; 前言什么是 GitHub1s&#xff1f;使用 GitHub1s 阅读 browser-use 项目源码步骤 1: 打开 GitHub 项目页面步骤 2: 修改 URL 使用 GitHub1s步骤 3: 浏览文件结构步骤 4: 使用代码高亮和智能补全功能步骤 5: 快速跳转和…

修改el-select下拉框高度;更新:支持动态修改

文章目录 效果动态修改&#xff1a;效果代码固定高度版本动态修改高度版本&#xff08;2024-12-25 更新&#xff1a; 支持动态修改下拉框高度&#xff09; 效果 动态修改&#xff1a;效果 代码 固定高度版本 注意点&#xff1a; popper-class 尽量独一无二&#xff0c;防止影…

windows C#-显式实现接口成员

本示例声明一个接口IDimensions 和一个类 Box&#xff0c;显式实现了接口成员 GetLength 和 GetWidth。 通过接口实例 dimensions 访问这些成员。 interface IDimensions {float GetLength();float GetWidth(); }class Box : IDimensions {float lengthInches;float widthInch…

JavaFX FXML模式下的布局

常见布局方式概述 在 JavaFX FXML 模式下&#xff0c;有多种布局方式可供选择。这些布局方式可以帮助您有效地组织和排列 UI 组件&#xff0c;以创建出美观且功能良好的用户界面。常用布局容器及布局方式 BorderPane 布局 特点&#xff1a;BorderPane 将空间划分为五个区域&…

设计模式-责任链模式

一、简介 责任链模式&#xff08;Chain of Responsibility Pattern&#xff09;是一种行为型设计模式&#xff0c;用于将请求的发送者与接收者解耦&#xff0c;使多个处理对象都有机会处理该请求。这些处理对象通过形成一条链式结构依次处理请求&#xff0c;直到某个对象能够完…

Excel 列名称转换问题 Swift 解答

文章目录 摘要描述题解答案Swift 实现代码&#xff1a;题解代码分析示例测试及结果 时间复杂度空间复杂度总结未来展望参考资料 摘要 本篇文章将通过 Swift 编程语言解答一个常见的算法问题&#xff1a;给定一个整数 columnNumber&#xff0c;将其转换为 Excel 表中的列名称。…

TP5 动态渲染多个Layui表格并批量打印所有表格

记录&#xff1a; TP5 动态渲染多个Layui表格每个表格设置有2行表头&#xff0c;并且第一行表头在页面完成后动态渲染显示内容每个表格下面显示统计信息可点击字段排序一次打印页面上的所有表格打印页面上多个table时,让每个table单独一页 后端代码示例&#xff1a; /*** Nod…