Java geek

1. Dynamic scaling of resource pools

1. To improve the performance of the resource pool, set the minimum number of idle resources to complete the initialization of the resource pool. When the resource used exceeds the minimum idle resource number, the consumer will shrink to the minimum idle resource number after releasing it back into the pool for a certain time.

2. To avoid overload caused by unlimited resource application, set the maximum number of resources. The maximum number of resources in the pool cannot exceed the maximum number of resources.

2. Dynamically scale related class structures


class Duties and responsibilities
HouseKeeper The Runnable interface is implemented to dynamically scale pool resources.
ScheduledExecutorService Responsible for scheduling fixtures.
ScheduledFuture Returned by ScheduledExecutorService, the HouseKeeper can be terminated.
HikariPool Responsible for initializing and calling the above classes in the constructor.

3. The source code

3.1. HikariPool

      // Initialize ScheduledExecutorService
      this.houseKeepingExecutorService = initializeHouseKeepingExecutorService();
      
      // scheduling, delay and periodic scheduling
      this.houseKeeperTask = houseKeepingExecutorService.scheduleWithFixedDelay(new HouseKeeper(), 100L, housekeepingPeriodMs, MILLISECONDS);
Copy the code

3.2.HouseKeeper

   private final class HouseKeeper implements Runnable
   {
      private volatile long previous = plusMillis(currentTime(), -housekeepingPeriodMs);

      @Override
      public void run(a)
      {
         try {
            // refresh values in case they changed via MBeanconnectionTimeout = config.getConnectionTimeout(); validationTimeout = config.getValidationTimeout(); leakTaskFactory.updateLeakDetectionThreshold(config.getLeakDetectionThreshold()); catalog = (config.getCatalog() ! =null && !config.getCatalog().equals(catalog)) ? config.getCatalog() : catalog;

            final long idleTimeout = config.getIdleTimeout();
            final long now = currentTime();

            // Detect retrograde time, allowing +128ms as per NTP spec.
            if (plusMillis(now, 128) < plusMillis(previous, housekeepingPeriodMs)) {
               logger.warn("{} - Retrograde clock change detected (housekeeper delta={}), soft-evicting connections from pool.",
                           poolName, elapsedDisplayString(previous, now));
               previous = now;
               softEvictConnections();
               return;
            }
            else if (now > plusMillis(previous, (3 * housekeepingPeriodMs) / 2)) {
               // No point evicting for forward clock motion, this merely accelerates connection retirement anyway
               logger.warn("{} - Thread starvation or clock leap detected (housekeeper delta={}).", poolName, elapsedDisplayString(previous, now));
            }

            previous = now;

            String afterPrefix = "Pool ";
            if (idleTimeout > 0L && config.getMinimumIdle() < config.getMaximumPoolSize()) {
               logPoolState("Before cleanup ");
               afterPrefix = "After cleanup ";
               
               // Get an unused resource
               final List<PoolEntry> notInUse = connectionBag.values(STATE_NOT_IN_USE);
               // If the unused resource is greater than the configured minimum idle resource, close the excess resource
               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--;
                  }
               }
            }

            logPoolState(afterPrefix);
            
            // In addition to dynamically reducing resources, here dynamically expanding resources
            fillPool(); // Try to maintain minimum connections
         }
         catch (Exception e) {
            logger.error("Unexpected exception in housekeeping task", e); }}}Copy the code

Dynamic resource expansion:

//HikariPool.java
   private synchronized void fillPool(a)
   {
      final int connectionsToAdd = Math.min(config.getMaximumPoolSize() - getTotalConnections(), config.getMinimumIdle() - getIdleConnections())
                                   - addConnectionQueue.size();
      for (int i = 0; i < connectionsToAdd; i++) {
         addConnectionExecutor.submit((i < connectionsToAdd - 1)? poolEntryCreator : postFillPoolEntryCreator); }}Copy the code

3.3. Load-balanced across

Releasing a resource in ConcurrentBag changes the state of the resource and does not change the number of available resources in the resource pool.

   public void requite(final T bagEntry)
   {
      // This is only a modification of the resource state. It does not reduce the number of available resources in the resource pool.
      bagEntry.setState(STATE_NOT_IN_USE);

      for (int i = 0; waiters.get() > 0; i++) {
         if(bagEntry.getState() ! = STATE_NOT_IN_USE || handoffQueue.offer(bagEntry)) {return;
         }
         else if ((i & 0xff) = =0xff) { // 0xff is 255, which is entered at 256 intervals
            parkNanos(MICROSECONDS.toNanos(10));
         }
         else{ yield(); }}final List<Object> threadLocalList = threadList.get();
      if (threadLocalList.size() < 50) {
         threadLocalList.add(weakThreadLocals ? newWeakReference<>(bagEntry) : bagEntry); }}Copy the code

4. To summarize

  1. The minimum number of resources in a resource pool is initialized.
  2. Dynamic scaling of resources can be accomplished by scheduling threads using the JUC tool ScheduledExecutorService, without the need for third-party timers.
  3. When a consumer releases a resource, it does not immediately reduce the amount of available resources in the resource pool, because it is likely that other consumers will apply for resources again. To avoid reducing unnecessary resource creation operations, the released resource should be closed after a certain period of time.

end.


<– Thanks for the triple punch, left likes and followings.


Related reading: HikariPool source code (a) first HikariPool source code (two) design ideas for reference HikariPool source code (four) resource state HikariPool source code (five) thread and related tools HikariPool source code (six) to use some useful JAVA features


Java geek site: javageektour.com/