HikariPool 鏈接池在初始化的時候主要作了幾件事:java
public HikariPool(final HikariConfig config) { super(config); // 1. 構建自定義的線程池容器 ConcurrentBag this.connectionBag = new ConcurrentBag<>(this); this.suspendResumeLock = config.isAllowPoolSuspension() ? new SuspendResumeLock() : SuspendResumeLock.FAUX_LOCK; this.houseKeepingExecutorService = initializeHouseKeepingExecutorService(); // 2. 建立鏈接,校驗有效性 快速失敗 checkFailFast(); // 若是傳入opentracing的 metricsTracker就能夠上報鏈接池的一些指標信息 if (config.getMetricsTrackerFactory() != null) { setMetricsTrackerFactory(config.getMetricsTrackerFactory()); } else { setMetricRegistry(config.getMetricRegistry()); } setHealthCheckRegistry(config.getHealthCheckRegistry()); handleMBeans(this, true); ThreadFactory threadFactory = config.getThreadFactory(); final int maxPoolSize = config.getMaximumPoolSize(); // 3. 鏈接新增線程池的 blockQueue,上限爲 maxPoolSize LinkedBlockingQueue<Runnable> addConnectionQueue = new LinkedBlockingQueue<>(maxPoolSize); // 4. addConnectionQueueReadOnlyView 用來查看當前有幾個db鏈接任務 this.addConnectionQueueReadOnlyView = unmodifiableCollection(addConnectionQueue); // 5. 構建負責新建db鏈接的線程池,1個工做線程、隊列上限maxPoolSize this.addConnectionExecutor = createThreadPoolExecutor(addConnectionQueue, poolName + " connection adder", threadFactory, new ThreadPoolExecutor.DiscardOldestPolicy()); // 6. 構建負責關閉db鏈接的線程池,1個工做線程、隊列上限maxPoolSize this.closeConnectionExecutor = createThreadPoolExecutor(maxPoolSize, poolName + " connection closer", threadFactory, new ThreadPoolExecutor.CallerRunsPolicy()); // 7. 鏈接泄露檢測(leakDetectionThreshold默認爲0,不開啓),db鏈接從池子中取出後開始計時,若是超過必定的時長還未歸還則認爲可能發現鏈接泄露/慢查詢了 this.leakTaskFactory = new ProxyLeakTaskFactory(config.getLeakDetectionThreshold(), houseKeepingExecutorService); // 8. houseKeepingExecutor 定時任務,用來維護鏈接池內 minimumIdle個鏈接 // 間隔30ms檢查一次鏈接池,若是不足 minimumIlde則填充,超過minimumIlde~maxPoolSize的那部分鏈接若是空閒時長 > idleTimeout則關閉掉 this.houseKeeperTask = houseKeepingExecutorService.scheduleWithFixedDelay(**new HouseKeeper()**, 100L, housekeepingPeriodMs, MILLISECONDS); // 若是系統變量設置的阻塞等待 鏈接池填充完畢,則會等待 houseKeeperTask 把鏈接池填充完畢 if (Boolean.getBoolean("com.zaxxer.hikari.blockUntilFilled") && config.getInitializationFailTimeout() > 1) { // 給負責新建db鏈接的線程池 加大火力 addConnectionExecutor.setCorePoolSize(Math.min(16, Runtime.getRuntime().availableProcessors())); addConnectionExecutor.setMaximumPoolSize(Math.min(16, Runtime.getRuntime().availableProcessors())); final long startTime = currentTime(); while (elapsedMillis(startTime) < config.getInitializationFailTimeout() && getTotalConnections() < config.getMinimumIdle()) { quietlySleep(MILLISECONDS.toMillis(100)); } addConnectionExecutor.setCorePoolSize(1); addConnectionExecutor.setMaximumPoolSize(1); } }
幾個關鍵對象:ide
String afterPrefix = "Pool "; if (idleTimeout > 0L && config.getMinimumIdle() < config.getMaximumPoolSize()) { logPoolState("Before cleanup "); afterPrefix = "After cleanup "; final List<PoolEntry> notInUse = connectionBag.values(**STATE_NOT_IN_USE**); int toRemove = notInUse.size() - config.getMinimumIdle(); for (PoolEntry entry : notInUse) { if (toRemove > 0 && elapsedMillis(entry.lastAccessed, now) > idleTimeout && connectionBag.reserve(entry)) { closeConnection(entry, "(connection has passed idleTimeout)"); toRemove--; } } }
fillPool();
空閒db鏈接數補足到 minimumIdle 個private synchronized void fillPool() { final int connectionsToAdd = Math.min(config.getMaximumPoolSize() - getTotalConnections(), config.getMinimumIdle() - getIdleConnections()) - addConnectionQueueReadOnlyView.size(); //這時候 addConnectionExecutor 的隊列視圖就有用了 if (connectionsToAdd <= 0) logger.debug("{} - Fill pool skipped, pool is at sufficient level.", poolName); for (int i = 0; i < connectionsToAdd; i++) { addConnectionExecutor.submit((i < connectionsToAdd - 1) ? poolEntryCreator : postFillPoolEntryCreator); } }