001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.commons.pool2.impl; 018 019import java.io.PrintWriter; 020import java.io.StringWriter; 021import java.io.Writer; 022import java.lang.management.ManagementFactory; 023import java.lang.ref.WeakReference; 024import java.lang.reflect.InvocationTargetException; 025import java.time.Duration; 026import java.util.Arrays; 027import java.util.Deque; 028import java.util.Iterator; 029import java.util.TimerTask; 030import java.util.concurrent.ScheduledFuture; 031import java.util.concurrent.atomic.AtomicLong; 032 033import javax.management.InstanceAlreadyExistsException; 034import javax.management.InstanceNotFoundException; 035import javax.management.MBeanRegistrationException; 036import javax.management.MBeanServer; 037import javax.management.MalformedObjectNameException; 038import javax.management.NotCompliantMBeanException; 039import javax.management.ObjectName; 040 041import org.apache.commons.pool2.BaseObject; 042import org.apache.commons.pool2.PooledObject; 043import org.apache.commons.pool2.PooledObjectState; 044import org.apache.commons.pool2.SwallowedExceptionListener; 045 046/** 047 * Base class that provides common functionality for {@link GenericObjectPool} 048 * and {@link GenericKeyedObjectPool}. The primary reason this class exists is 049 * reduce code duplication between the two pool implementations. 050 * 051 * @param <T> Type of element pooled in this pool. 052 * 053 * This class is intended to be thread-safe. 054 * 055 * @since 2.0 056 */ 057public abstract class BaseGenericObjectPool<T> extends BaseObject { 058 059 /** 060 * The idle object eviction iterator. Holds a reference to the idle objects. 061 */ 062 class EvictionIterator implements Iterator<PooledObject<T>> { 063 064 private final Deque<PooledObject<T>> idleObjects; 065 private final Iterator<PooledObject<T>> idleObjectIterator; 066 067 /** 068 * Create an EvictionIterator for the provided idle instance deque. 069 * @param idleObjects underlying deque 070 */ 071 EvictionIterator(final Deque<PooledObject<T>> idleObjects) { 072 this.idleObjects = idleObjects; 073 074 if (getLifo()) { 075 idleObjectIterator = idleObjects.descendingIterator(); 076 } else { 077 idleObjectIterator = idleObjects.iterator(); 078 } 079 } 080 081 /** 082 * Gets the idle object deque referenced by this iterator. 083 * @return the idle object deque 084 */ 085 public Deque<PooledObject<T>> getIdleObjects() { 086 return idleObjects; 087 } 088 089 /** {@inheritDoc} */ 090 @Override 091 public boolean hasNext() { 092 return idleObjectIterator.hasNext(); 093 } 094 095 /** {@inheritDoc} */ 096 @Override 097 public PooledObject<T> next() { 098 return idleObjectIterator.next(); 099 } 100 101 /** {@inheritDoc} */ 102 @Override 103 public void remove() { 104 idleObjectIterator.remove(); 105 } 106 107 } 108 109 /** 110 * The idle object evictor {@link TimerTask}. 111 * 112 * @see GenericKeyedObjectPool#setTimeBetweenEvictionRunsMillis 113 */ 114 class Evictor implements Runnable { 115 116 private ScheduledFuture<?> scheduledFuture; 117 118 /** 119 * Cancels the scheduled future. 120 */ 121 void cancel() { 122 scheduledFuture.cancel(false); 123 } 124 125 126 /** 127 * Run pool maintenance. Evict objects qualifying for eviction and then 128 * ensure that the minimum number of idle instances are available. 129 * Since the Timer that invokes Evictors is shared for all Pools but 130 * pools may exist in different class loaders, the Evictor ensures that 131 * any actions taken are under the class loader of the factory 132 * associated with the pool. 133 */ 134 @Override 135 public void run() { 136 final ClassLoader savedClassLoader = 137 Thread.currentThread().getContextClassLoader(); 138 try { 139 if (factoryClassLoader != null) { 140 // Set the class loader for the factory 141 final ClassLoader cl = factoryClassLoader.get(); 142 if (cl == null) { 143 // The pool has been dereferenced and the class loader 144 // GC'd. Cancel this timer so the pool can be GC'd as 145 // well. 146 cancel(); 147 return; 148 } 149 Thread.currentThread().setContextClassLoader(cl); 150 } 151 152 // Evict from the pool 153 try { 154 evict(); 155 } catch(final Exception e) { 156 swallowException(e); 157 } catch(final OutOfMemoryError oome) { 158 // Log problem but give evictor thread a chance to continue 159 // in case error is recoverable 160 oome.printStackTrace(System.err); 161 } 162 // Re-create idle instances. 163 try { 164 ensureMinIdle(); 165 } catch (final Exception e) { 166 swallowException(e); 167 } 168 } finally { 169 // Restore the previous CCL 170 Thread.currentThread().setContextClassLoader(savedClassLoader); 171 } 172 } 173 174 175 /** 176 * Sets the scheduled future. 177 * 178 * @param scheduledFuture the scheduled future. 179 */ 180 void setScheduledFuture(final ScheduledFuture<?> scheduledFuture) { 181 this.scheduledFuture = scheduledFuture; 182 } 183 184 } 185 186 /** 187 * Wrapper for objects under management by the pool. 188 * 189 * GenericObjectPool and GenericKeyedObjectPool maintain references to all 190 * objects under management using maps keyed on the objects. This wrapper 191 * class ensures that objects can work as hash keys. 192 * 193 * @param <T> type of objects in the pool 194 */ 195 static class IdentityWrapper<T> { 196 /** Wrapped object */ 197 private final T instance; 198 199 /** 200 * Create a wrapper for an instance. 201 * 202 * @param instance object to wrap 203 */ 204 public IdentityWrapper(final T instance) { 205 this.instance = instance; 206 } 207 208 @Override 209 @SuppressWarnings("rawtypes") 210 public boolean equals(final Object other) { 211 return other instanceof IdentityWrapper && 212 ((IdentityWrapper) other).instance == instance; 213 } 214 215 /** 216 * @return the wrapped object 217 */ 218 public T getObject() { 219 return instance; 220 } 221 222 @Override 223 public int hashCode() { 224 return System.identityHashCode(instance); 225 } 226 227 @Override 228 public String toString() { 229 final StringBuilder builder = new StringBuilder(); 230 builder.append("IdentityWrapper [instance="); 231 builder.append(instance); 232 builder.append("]"); 233 return builder.toString(); 234 } 235 } 236 /** 237 * Maintains a cache of values for a single metric and reports 238 * statistics on the cached values. 239 */ 240 private class StatsStore { 241 242 private final AtomicLong[] values; 243 private final int size; 244 private int index; 245 246 /** 247 * Create a StatsStore with the given cache size. 248 * 249 * @param size number of values to maintain in the cache. 250 */ 251 StatsStore(final int size) { 252 this.size = size; 253 values = new AtomicLong[size]; 254 for (int i = 0; i < size; i++) { 255 values[i] = new AtomicLong(-1); 256 } 257 } 258 259 void add(final Duration value) { 260 add(value.toMillis()); 261 } 262 263 /** 264 * Adds a value to the cache. If the cache is full, one of the 265 * existing values is replaced by the new value. 266 * 267 * @param value new value to add to the cache. 268 */ 269 synchronized void add(final long value) { 270 values[index].set(value); 271 index++; 272 if (index == size) { 273 index = 0; 274 } 275 } 276 277 /** 278 * Gets the mean of the cached values. 279 * 280 * @return the mean of the cache, truncated to long 281 */ 282 public long getMean() { 283 double result = 0; 284 int counter = 0; 285 for (int i = 0; i < size; i++) { 286 final long value = values[i].get(); 287 if (value != -1) { 288 counter++; 289 result = result * ((counter - 1) / (double) counter) + 290 value/(double) counter; 291 } 292 } 293 return (long) result; 294 } 295 296 @Override 297 public String toString() { 298 final StringBuilder builder = new StringBuilder(); 299 builder.append("StatsStore [values="); 300 builder.append(Arrays.toString(values)); 301 builder.append(", size="); 302 builder.append(size); 303 builder.append(", index="); 304 builder.append(index); 305 builder.append("]"); 306 return builder.toString(); 307 } 308 } 309 // Constants 310 /** 311 * The size of the caches used to store historical data for some attributes 312 * so that rolling means may be calculated. 313 */ 314 public static final int MEAN_TIMING_STATS_CACHE_SIZE = 100; 315 private static final String EVICTION_POLICY_TYPE_NAME = EvictionPolicy.class.getName(); 316 // Configuration attributes 317 private volatile int maxTotal = GenericKeyedObjectPoolConfig.DEFAULT_MAX_TOTAL; 318 private volatile boolean blockWhenExhausted = BaseObjectPoolConfig.DEFAULT_BLOCK_WHEN_EXHAUSTED; 319 private volatile Duration maxWait = BaseObjectPoolConfig.DEFAULT_MAX_WAIT; 320 private volatile boolean lifo = BaseObjectPoolConfig.DEFAULT_LIFO; 321 private final boolean fairness; 322 private volatile boolean testOnCreate = BaseObjectPoolConfig.DEFAULT_TEST_ON_CREATE; 323 private volatile boolean testOnBorrow = BaseObjectPoolConfig.DEFAULT_TEST_ON_BORROW; 324 private volatile boolean testOnReturn = BaseObjectPoolConfig.DEFAULT_TEST_ON_RETURN; 325 private volatile boolean testWhileIdle = BaseObjectPoolConfig.DEFAULT_TEST_WHILE_IDLE; 326 private volatile Duration timeBetweenEvictionRuns = BaseObjectPoolConfig.DEFAULT_TIME_BETWEEN_EVICTION_RUNS; 327 private volatile int numTestsPerEvictionRun = BaseObjectPoolConfig.DEFAULT_NUM_TESTS_PER_EVICTION_RUN; 328 329 private volatile Duration minEvictableIdleTime = BaseObjectPoolConfig.DEFAULT_MIN_EVICTABLE_IDLE_TIME; 330 private volatile Duration softMinEvictableIdleTime = BaseObjectPoolConfig.DEFAULT_SOFT_MIN_EVICTABLE_IDLE_TIME; 331 private volatile EvictionPolicy<T> evictionPolicy; 332 private volatile Duration evictorShutdownTimeout = BaseObjectPoolConfig.DEFAULT_EVICTOR_SHUTDOWN_TIMEOUT; 333 // Internal (primarily state) attributes 334 final Object closeLock = new Object(); 335 volatile boolean closed; 336 337 338 final Object evictionLock = new Object(); 339 private Evictor evictor = null; // @GuardedBy("evictionLock") 340 EvictionIterator evictionIterator = null; // @GuardedBy("evictionLock") 341 /* 342 * Class loader for evictor thread to use since, in a JavaEE or similar 343 * environment, the context class loader for the evictor thread may not have 344 * visibility of the correct factory. See POOL-161. Uses a weak reference to 345 * avoid potential memory leaks if the Pool is discarded rather than closed. 346 */ 347 private final WeakReference<ClassLoader> factoryClassLoader; 348 // Monitoring (primarily JMX) attributes 349 private final ObjectName objectName; 350 private final String creationStackTrace; 351 private final AtomicLong borrowedCount = new AtomicLong(0); 352 private final AtomicLong returnedCount = new AtomicLong(0); 353 final AtomicLong createdCount = new AtomicLong(0); 354 final AtomicLong destroyedCount = new AtomicLong(0); 355 final AtomicLong destroyedByEvictorCount = new AtomicLong(0); 356 final AtomicLong destroyedByBorrowValidationCount = new AtomicLong(0); 357 private final StatsStore activeTimes = new StatsStore(MEAN_TIMING_STATS_CACHE_SIZE); 358 359 360 private final StatsStore idleTimes = new StatsStore(MEAN_TIMING_STATS_CACHE_SIZE); 361 362 363 private final StatsStore waitTimes = new StatsStore(MEAN_TIMING_STATS_CACHE_SIZE); 364 365 private final AtomicLong maxBorrowWaitTimeMillis = new AtomicLong(0L); 366 367 private volatile SwallowedExceptionListener swallowedExceptionListener = null; 368 369 /** 370 * Handles JMX registration (if required) and the initialization required for 371 * monitoring. 372 * 373 * @param config Pool configuration 374 * @param jmxNameBase The default base JMX name for the new pool unless 375 * overridden by the config 376 * @param jmxNamePrefix Prefix to be used for JMX name for the new pool 377 */ 378 public BaseGenericObjectPool(final BaseObjectPoolConfig<T> config, 379 final String jmxNameBase, final String jmxNamePrefix) { 380 if (config.getJmxEnabled()) { 381 this.objectName = jmxRegister(config, jmxNameBase, jmxNamePrefix); 382 } else { 383 this.objectName = null; 384 } 385 386 // Populate the creation stack trace 387 this.creationStackTrace = getStackTrace(new Exception()); 388 389 // save the current TCCL (if any) to be used later by the evictor Thread 390 final ClassLoader cl = Thread.currentThread().getContextClassLoader(); 391 if (cl == null) { 392 factoryClassLoader = null; 393 } else { 394 factoryClassLoader = new WeakReference<>(cl); 395 } 396 397 fairness = config.getFairness(); 398 } 399 400 /** 401 * Verifies that the pool is open. 402 * @throws IllegalStateException if the pool is closed. 403 */ 404 final void assertOpen() throws IllegalStateException { 405 if (isClosed()) { 406 throw new IllegalStateException("Pool not open"); 407 } 408 } 409 410 /** 411 * Closes the pool, destroys the remaining idle objects and, if registered 412 * in JMX, deregisters it. 413 */ 414 public abstract void close(); 415 416 /** 417 * Tries to ensure that the configured minimum number of idle instances are 418 * available in the pool. 419 * @throws Exception if an error occurs creating idle instances 420 */ 421 abstract void ensureMinIdle() throws Exception; 422 423 /** 424 * <p>Perform {@code numTests} idle object eviction tests, evicting 425 * examined objects that meet the criteria for eviction. If 426 * {@code testWhileIdle} is true, examined objects are validated 427 * when visited (and removed if invalid); otherwise only objects that 428 * have been idle for more than {@code minEvicableIdleTimeMillis} 429 * are removed.</p> 430 * 431 * @throws Exception when there is a problem evicting idle objects. 432 */ 433 public abstract void evict() throws Exception; 434 435 /** 436 * Gets whether to block when the {@code borrowObject()} method is 437 * invoked when the pool is exhausted (the maximum number of "active" 438 * objects has been reached). 439 * 440 * @return {@code true} if {@code borrowObject()} should block 441 * when the pool is exhausted 442 * 443 * @see #setBlockWhenExhausted 444 */ 445 public final boolean getBlockWhenExhausted() { 446 return blockWhenExhausted; 447 } 448 449 /** 450 * The total number of objects successfully borrowed from this pool over the 451 * lifetime of the pool. 452 * @return the borrowed object count 453 */ 454 public final long getBorrowedCount() { 455 return borrowedCount.get(); 456 } 457 458 /** 459 * The total number of objects created for this pool over the lifetime of 460 * the pool. 461 * @return the created object count 462 */ 463 public final long getCreatedCount() { 464 return createdCount.get(); 465 } 466 467 /** 468 * Provides the stack trace for the call that created this pool. JMX 469 * registration may trigger a memory leak so it is important that pools are 470 * deregistered when no longer used by calling the {@link #close()} method. 471 * This method is provided to assist with identifying code that creates but 472 * does not close it thereby creating a memory leak. 473 * @return pool creation stack trace 474 */ 475 public final String getCreationStackTrace() { 476 return creationStackTrace; 477 } 478 479 /** 480 * The total number of objects destroyed by this pool as a result of failing 481 * validation during {@code borrowObject()} over the lifetime of the 482 * pool. 483 * @return validation destroyed object count 484 */ 485 public final long getDestroyedByBorrowValidationCount() { 486 return destroyedByBorrowValidationCount.get(); 487 } 488 489 /** 490 * The total number of objects destroyed by the evictor associated with this 491 * pool over the lifetime of the pool. 492 * @return the evictor destroyed object count 493 */ 494 public final long getDestroyedByEvictorCount() { 495 return destroyedByEvictorCount.get(); 496 } 497 498 /** 499 * The total number of objects destroyed by this pool over the lifetime of 500 * the pool. 501 * @return the destroyed object count 502 */ 503 public final long getDestroyedCount() { 504 return destroyedCount.get(); 505 } 506 507 /** 508 * Gets the {@link EvictionPolicy} defined for this pool. 509 * 510 * @return the eviction policy 511 * @since 2.4 512 * @since 2.6.0 Changed access from protected to public. 513 */ 514 public EvictionPolicy<T> getEvictionPolicy() { 515 return evictionPolicy; 516 } 517 518 /** 519 * Gets the name of the {@link EvictionPolicy} implementation that is 520 * used by this pool. 521 * 522 * @return The fully qualified class name of the {@link EvictionPolicy} 523 * 524 * @see #setEvictionPolicyClassName(String) 525 */ 526 public final String getEvictionPolicyClassName() { 527 return evictionPolicy.getClass().getName(); 528 } 529 530 /** 531 * Gets the timeout that will be used when waiting for the Evictor to 532 * shutdown if this pool is closed and it is the only pool still using the 533 * the value for the Evictor. 534 * 535 * @return The timeout that will be used while waiting for 536 * the Evictor to shut down. 537 * @since 2.10.0 538 */ 539 public final Duration getEvictorShutdownTimeout() { 540 return evictorShutdownTimeout; 541 } 542 543 /** 544 * Gets the timeout that will be used when waiting for the Evictor to 545 * shutdown if this pool is closed and it is the only pool still using the 546 * the value for the Evictor. 547 * 548 * @return The timeout in milliseconds that will be used while waiting for 549 * the Evictor to shut down. 550 * @deprecated Use {@link #getEvictorShutdownTimeout()}. 551 */ 552 @Deprecated 553 public final long getEvictorShutdownTimeoutMillis() { 554 return evictorShutdownTimeout.toMillis(); 555 } 556 557 /** 558 * Gets whether or not the pool serves threads waiting to borrow objects fairly. 559 * True means that waiting threads are served as if waiting in a FIFO queue. 560 * 561 * @return {@code true} if waiting threads are to be served 562 * by the pool in arrival order 563 */ 564 public final boolean getFairness() { 565 return fairness; 566 } 567 568 /** 569 * Provides the name under which the pool has been registered with the 570 * platform MBean server or {@code null} if the pool has not been 571 * registered. 572 * @return the JMX name 573 */ 574 public final ObjectName getJmxName() { 575 return objectName; 576 } 577 578 /** 579 * Gets whether the pool has LIFO (last in, first out) behavior with 580 * respect to idle objects - always returning the most recently used object 581 * from the pool, or as a FIFO (first in, first out) queue, where the pool 582 * always returns the oldest object in the idle object pool. 583 * 584 * @return {@code true} if the pool is configured with LIFO behavior 585 * or {@code false} if the pool is configured with FIFO 586 * behavior 587 * 588 * @see #setLifo 589 */ 590 public final boolean getLifo() { 591 return lifo; 592 } 593 594 /** 595 * The maximum time a thread has waited to borrow objects from the pool. 596 * @return maximum wait time in milliseconds since the pool was created 597 */ 598 public final long getMaxBorrowWaitTimeMillis() { 599 return maxBorrowWaitTimeMillis.get(); 600 } 601 602 /** 603 * Gets the maximum number of objects that can be allocated by the pool 604 * (checked out to clients, or idle awaiting checkout) at a given time. When 605 * negative, there is no limit to the number of objects that can be 606 * managed by the pool at one time. 607 * 608 * @return the cap on the total number of object instances managed by the 609 * pool. 610 * 611 * @see #setMaxTotal 612 */ 613 public final int getMaxTotal() { 614 return maxTotal; 615 } 616 617 /** 618 * Gets the maximum amount of time (in milliseconds) the 619 * {@code borrowObject()} method should block before throwing an 620 * exception when the pool is exhausted and 621 * {@link #getBlockWhenExhausted} is true. When less than 0, the 622 * {@code borrowObject()} method may block indefinitely. 623 * 624 * @return the maximum number of milliseconds {@code borrowObject()} 625 * will block. 626 * 627 * @see #setMaxWaitMillis 628 * @see #setBlockWhenExhausted 629 */ 630 public final long getMaxWaitMillis() { 631 return maxWait.toMillis(); 632 } 633 634 /** 635 * The mean time objects are active for based on the last {@link 636 * #MEAN_TIMING_STATS_CACHE_SIZE} objects returned to the pool. 637 * @return mean time an object has been checked out from the pool among 638 * recently returned objects 639 */ 640 public final long getMeanActiveTimeMillis() { 641 return activeTimes.getMean(); 642 } 643 644 /** 645 * The mean time threads wait to borrow an object based on the last {@link 646 * #MEAN_TIMING_STATS_CACHE_SIZE} objects borrowed from the pool. 647 * @return mean time in milliseconds that a recently served thread has had 648 * to wait to borrow an object from the pool 649 */ 650 public final long getMeanBorrowWaitTimeMillis() { 651 return waitTimes.getMean(); 652 } 653 654 /** 655 * The mean time objects are idle for based on the last {@link 656 * #MEAN_TIMING_STATS_CACHE_SIZE} objects borrowed from the pool. 657 * @return mean time an object has been idle in the pool among recently 658 * borrowed objects 659 */ 660 public final long getMeanIdleTimeMillis() { 661 return idleTimes.getMean(); 662 } 663 664 /** 665 * Gets the minimum amount of time an object may sit idle in the pool 666 * before it is eligible for eviction by the idle object evictor (if any - 667 * see {@link #setTimeBetweenEvictionRuns(Duration)}). When non-positive, 668 * no objects will be evicted from the pool due to idle time alone. 669 * 670 * @return minimum amount of time an object may sit idle in the pool before 671 * it is eligible for eviction 672 * 673 * @see #setMinEvictableIdleTimeMillis 674 * @see #setTimeBetweenEvictionRunsMillis 675 * @since 2.10.0 676 */ 677 public final Duration getMinEvictableIdleTime() { 678 return minEvictableIdleTime; 679 } 680 681 /** 682 * Gets the minimum amount of time an object may sit idle in the pool 683 * before it is eligible for eviction by the idle object evictor (if any - 684 * see {@link #setTimeBetweenEvictionRunsMillis(long)}). When non-positive, 685 * no objects will be evicted from the pool due to idle time alone. 686 * 687 * @return minimum amount of time an object may sit idle in the pool before 688 * it is eligible for eviction 689 * 690 * @see #setMinEvictableIdleTimeMillis 691 * @see #setTimeBetweenEvictionRunsMillis 692 * @deprecated Use {@link #getMinEvictableIdleTime()}. 693 */ 694 @Deprecated 695 public final long getMinEvictableIdleTimeMillis() { 696 return minEvictableIdleTime.toMillis(); 697 } 698 699 /** 700 * The number of instances currently idle in this pool. 701 * @return count of instances available for checkout from the pool 702 */ 703 public abstract int getNumIdle(); 704 705 /** 706 * Gets the maximum number of objects to examine during each run (if any) 707 * of the idle object evictor thread. When positive, the number of tests 708 * performed for a run will be the minimum of the configured value and the 709 * number of idle instances in the pool. When negative, the number of tests 710 * performed will be <code>ceil({@link #getNumIdle}/ 711 * abs({@link #getNumTestsPerEvictionRun}))</code> which means that when the 712 * value is {@code -n} roughly one nth of the idle objects will be 713 * tested per run. 714 * 715 * @return max number of objects to examine during each evictor run 716 * 717 * @see #setNumTestsPerEvictionRun 718 * @see #setTimeBetweenEvictionRunsMillis 719 */ 720 public final int getNumTestsPerEvictionRun() { 721 return numTestsPerEvictionRun; 722 } 723 724 /** 725 * The total number of objects returned to this pool over the lifetime of 726 * the pool. This excludes attempts to return the same object multiple 727 * times. 728 * @return the returned object count 729 */ 730 public final long getReturnedCount() { 731 return returnedCount.get(); 732 } 733 734 /** 735 * Gets the minimum amount of time an object may sit idle in the pool 736 * before it is eligible for eviction by the idle object evictor (if any - 737 * see {@link #setTimeBetweenEvictionRuns(Duration)}), 738 * with the extra condition that at least {@code minIdle} object 739 * instances remain in the pool. This setting is overridden by 740 * {@link #getMinEvictableIdleTime} (that is, if 741 * {@link #getMinEvictableIdleTime} is positive, then 742 * {@link #getSoftMinEvictableIdleTime} is ignored). 743 * 744 * @return minimum amount of time an object may sit idle in the pool before 745 * it is eligible for eviction if minIdle instances are available 746 * 747 * @see #setSoftMinEvictableIdleTime(Duration) 748 * @since 2.10.0 749 */ 750 public final Duration getSoftMinEvictableIdleTime() { 751 return softMinEvictableIdleTime; 752 } 753 754 /** 755 * Gets the minimum amount of time an object may sit idle in the pool 756 * before it is eligible for eviction by the idle object evictor (if any - 757 * see {@link #setTimeBetweenEvictionRunsMillis(long)}), 758 * with the extra condition that at least {@code minIdle} object 759 * instances remain in the pool. This setting is overridden by 760 * {@link #getMinEvictableIdleTimeMillis} (that is, if 761 * {@link #getMinEvictableIdleTimeMillis} is positive, then 762 * {@link #getSoftMinEvictableIdleTimeMillis} is ignored). 763 * 764 * @return minimum amount of time an object may sit idle in the pool before 765 * it is eligible for eviction if minIdle instances are available 766 * 767 * @see #setSoftMinEvictableIdleTimeMillis 768 * @deprecated Use {@link #getSoftMinEvictableIdleTime()}. 769 */ 770 @Deprecated 771 public final long getSoftMinEvictableIdleTimeMillis() { 772 return softMinEvictableIdleTime.toMillis(); 773 } 774 775 /** 776 * Gets the stack trace of an exception as a string. 777 * @param e exception to trace 778 * @return exception stack trace as a string 779 */ 780 private String getStackTrace(final Exception e) { 781 // Need the exception in string form to prevent the retention of 782 // references to classes in the stack trace that could trigger a memory 783 // leak in a container environment. 784 final Writer w = new StringWriter(); 785 final PrintWriter pw = new PrintWriter(w); 786 e.printStackTrace(pw); 787 return w.toString(); 788 } 789 790 /** 791 * The listener used (if any) to receive notifications of exceptions 792 * unavoidably swallowed by the pool. 793 * 794 * @return The listener or {@code null} for no listener 795 */ 796 public final SwallowedExceptionListener getSwallowedExceptionListener() { 797 return swallowedExceptionListener; 798 } 799 800 /** 801 * Gets whether objects borrowed from the pool will be validated before 802 * being returned from the {@code borrowObject()} method. Validation is 803 * performed by the {@code validateObject()} method of the factory 804 * associated with the pool. If the object fails to validate, it will be 805 * removed from the pool and destroyed, and a new attempt will be made to 806 * borrow an object from the pool. 807 * 808 * @return {@code true} if objects are validated before being returned 809 * from the {@code borrowObject()} method 810 * 811 * @see #setTestOnBorrow 812 */ 813 public final boolean getTestOnBorrow() { 814 return testOnBorrow; 815 } 816 817 /** 818 * Gets whether objects created for the pool will be validated before 819 * being returned from the {@code borrowObject()} method. Validation is 820 * performed by the {@code validateObject()} method of the factory 821 * associated with the pool. If the object fails to validate, then 822 * {@code borrowObject()} will fail. 823 * 824 * @return {@code true} if newly created objects are validated before 825 * being returned from the {@code borrowObject()} method 826 * 827 * @see #setTestOnCreate 828 * 829 * @since 2.2 830 */ 831 public final boolean getTestOnCreate() { 832 return testOnCreate; 833 } 834 835 /** 836 * Gets whether objects borrowed from the pool will be validated when 837 * they are returned to the pool via the {@code returnObject()} method. 838 * Validation is performed by the {@code validateObject()} method of 839 * the factory associated with the pool. Returning objects that fail validation 840 * are destroyed rather then being returned the pool. 841 * 842 * @return {@code true} if objects are validated on return to 843 * the pool via the {@code returnObject()} method 844 * 845 * @see #setTestOnReturn 846 */ 847 public final boolean getTestOnReturn() { 848 return testOnReturn; 849 } 850 851 /** 852 * Gets whether objects sitting idle in the pool will be validated by the 853 * idle object evictor (if any - see 854 * {@link #setTimeBetweenEvictionRuns(Duration)}). Validation is performed 855 * by the {@code validateObject()} method of the factory associated 856 * with the pool. If the object fails to validate, it will be removed from 857 * the pool and destroyed. 858 * 859 * @return {@code true} if objects will be validated by the evictor 860 * 861 * @see #setTestWhileIdle 862 * @see #setTimeBetweenEvictionRunsMillis 863 */ 864 public final boolean getTestWhileIdle() { 865 return testWhileIdle; 866 } 867 868 /** 869 * Gets the duration to sleep between runs of the idle 870 * object evictor thread. When non-positive, no idle object evictor thread 871 * will be run. 872 * 873 * @return number of milliseconds to sleep between evictor runs 874 * 875 * @see #setTimeBetweenEvictionRuns 876 * @since 2.10.0 877 */ 878 public final Duration getTimeBetweenEvictionRuns() { 879 return timeBetweenEvictionRuns; 880 } 881 882 /** 883 * Gets the number of milliseconds to sleep between runs of the idle 884 * object evictor thread. When non-positive, no idle object evictor thread 885 * will be run. 886 * 887 * @return number of milliseconds to sleep between evictor runs 888 * 889 * @see #setTimeBetweenEvictionRunsMillis 890 * @deprecated Use {@link #getTimeBetweenEvictionRuns()}. 891 */ 892 @Deprecated 893 public final long getTimeBetweenEvictionRunsMillis() { 894 return timeBetweenEvictionRuns.toMillis(); 895 } 896 897 /** 898 * Has this pool instance been closed. 899 * @return {@code true} when this pool has been closed. 900 */ 901 public final boolean isClosed() { 902 return closed; 903 } 904 905 /** 906 * Registers the pool with the platform MBean server. 907 * The registered name will be 908 * {@code jmxNameBase + jmxNamePrefix + i} where i is the least 909 * integer greater than or equal to 1 such that the name is not already 910 * registered. Swallows MBeanRegistrationException, NotCompliantMBeanException 911 * returning null. 912 * 913 * @param config Pool configuration 914 * @param jmxNameBase default base JMX name for this pool 915 * @param jmxNamePrefix name prefix 916 * @return registered ObjectName, null if registration fails 917 */ 918 private ObjectName jmxRegister(final BaseObjectPoolConfig<T> config, 919 final String jmxNameBase, String jmxNamePrefix) { 920 ObjectName newObjectName = null; 921 final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); 922 int i = 1; 923 boolean registered = false; 924 String base = config.getJmxNameBase(); 925 if (base == null) { 926 base = jmxNameBase; 927 } 928 while (!registered) { 929 try { 930 ObjectName objName; 931 // Skip the numeric suffix for the first pool in case there is 932 // only one so the names are cleaner. 933 if (i == 1) { 934 objName = new ObjectName(base + jmxNamePrefix); 935 } else { 936 objName = new ObjectName(base + jmxNamePrefix + i); 937 } 938 mbs.registerMBean(this, objName); 939 newObjectName = objName; 940 registered = true; 941 } catch (final MalformedObjectNameException e) { 942 if (BaseObjectPoolConfig.DEFAULT_JMX_NAME_PREFIX.equals( 943 jmxNamePrefix) && jmxNameBase.equals(base)) { 944 // Shouldn't happen. Skip registration if it does. 945 registered = true; 946 } else { 947 // Must be an invalid name. Use the defaults instead. 948 jmxNamePrefix = 949 BaseObjectPoolConfig.DEFAULT_JMX_NAME_PREFIX; 950 base = jmxNameBase; 951 } 952 } catch (final InstanceAlreadyExistsException e) { 953 // Increment the index and try again 954 i++; 955 } catch (final MBeanRegistrationException | NotCompliantMBeanException e) { 956 // Shouldn't happen. Skip registration if it does. 957 registered = true; 958 } 959 } 960 return newObjectName; 961 } 962 963 /** 964 * Unregisters this pool's MBean. 965 */ 966 final void jmxUnregister() { 967 if (objectName != null) { 968 try { 969 ManagementFactory.getPlatformMBeanServer().unregisterMBean( 970 objectName); 971 } catch (final MBeanRegistrationException | InstanceNotFoundException e) { 972 swallowException(e); 973 } 974 } 975 } 976 977 /** 978 * Marks the object as returning to the pool. 979 * @param pooledObject instance to return to the keyed pool 980 */ 981 protected void markReturningState(final PooledObject<T> pooledObject) { 982 synchronized(pooledObject) { 983 final PooledObjectState state = pooledObject.getState(); 984 if (state != PooledObjectState.ALLOCATED) { 985 throw new IllegalStateException( 986 "Object has already been returned to this pool or is invalid"); 987 } 988 pooledObject.markReturning(); // Keep from being marked abandoned 989 } 990 } 991 992 /** 993 * Sets whether to block when the {@code borrowObject()} method is 994 * invoked when the pool is exhausted (the maximum number of "active" 995 * objects has been reached). 996 * 997 * @param blockWhenExhausted {@code true} if 998 * {@code borrowObject()} should block 999 * when the pool is exhausted 1000 * 1001 * @see #getBlockWhenExhausted 1002 */ 1003 public final void setBlockWhenExhausted(final boolean blockWhenExhausted) { 1004 this.blockWhenExhausted = blockWhenExhausted; 1005 } 1006 /** 1007 * Initializes the receiver with the given configuration. 1008 * 1009 * @param config Initialization source. 1010 */ 1011 protected void setConfig(final BaseObjectPoolConfig<T> config) { 1012 setLifo(config.getLifo()); 1013 setMaxWaitMillis(config.getMaxWaitMillis()); 1014 setBlockWhenExhausted(config.getBlockWhenExhausted()); 1015 setTestOnCreate(config.getTestOnCreate()); 1016 setTestOnBorrow(config.getTestOnBorrow()); 1017 setTestOnReturn(config.getTestOnReturn()); 1018 setTestWhileIdle(config.getTestWhileIdle()); 1019 setNumTestsPerEvictionRun(config.getNumTestsPerEvictionRun()); 1020 setMinEvictableIdleTime(config.getMinEvictableIdleTime()); 1021 setTimeBetweenEvictionRuns(config.getTimeBetweenEvictionRuns()); 1022 setSoftMinEvictableIdleTime(config.getSoftMinEvictableIdleTime()); 1023 final EvictionPolicy<T> policy = config.getEvictionPolicy(); 1024 if (policy == null) { 1025 // Use the class name (pre-2.6.0 compatible) 1026 setEvictionPolicyClassName(config.getEvictionPolicyClassName()); 1027 } else { 1028 // Otherwise, use the class (2.6.0 feature) 1029 setEvictionPolicy(policy); 1030 } 1031 setEvictorShutdownTimeout(config.getEvictorShutdownTimeout()); 1032 } 1033 1034 1035 // Monitoring (primarily JMX) related methods 1036 1037 /** 1038 * Sets the eviction policy for this pool. 1039 * 1040 * @param evictionPolicy 1041 * the eviction policy for this pool. 1042 * @since 2.6.0 1043 */ 1044 public void setEvictionPolicy(final EvictionPolicy<T> evictionPolicy) { 1045 this.evictionPolicy = evictionPolicy; 1046 } 1047 1048 /** 1049 * Sets the eviction policy. 1050 * 1051 * @param className Eviction policy class name. 1052 * @param classLoader Load the class from this class loader. 1053 */ 1054 @SuppressWarnings("unchecked") 1055 private void setEvictionPolicy(final String className, final ClassLoader classLoader) 1056 throws ClassNotFoundException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException { 1057 final Class<?> clazz = Class.forName(className, true, classLoader); 1058 final Object policy = clazz.getConstructor().newInstance(); 1059 this.evictionPolicy = (EvictionPolicy<T>) policy; 1060 } 1061 1062 /** 1063 * Sets the name of the {@link EvictionPolicy} implementation that is used by this pool. The Pool will attempt to 1064 * load the class using the thread context class loader. If that fails, the use the class loader for the 1065 * {@link EvictionPolicy} interface. 1066 * 1067 * @param evictionPolicyClassName 1068 * the fully qualified class name of the new eviction policy 1069 * 1070 * @see #getEvictionPolicyClassName() 1071 * @since 2.6.0 If loading the class using the thread context class loader fails, use the class loader for the 1072 * {@link EvictionPolicy} interface. 1073 */ 1074 public final void setEvictionPolicyClassName(final String evictionPolicyClassName) { 1075 setEvictionPolicyClassName(evictionPolicyClassName, Thread.currentThread().getContextClassLoader()); 1076 } 1077 1078 /** 1079 * Sets the name of the {@link EvictionPolicy} implementation that is used by this pool. The Pool will attempt to 1080 * load the class using the given class loader. If that fails, use the class loader for the {@link EvictionPolicy} 1081 * interface. 1082 * 1083 * @param evictionPolicyClassName 1084 * the fully qualified class name of the new eviction policy 1085 * @param classLoader 1086 * the class loader to load the given {@code evictionPolicyClassName}. 1087 * 1088 * @see #getEvictionPolicyClassName() 1089 * @since 2.6.0 If loading the class using the given class loader fails, use the class loader for the 1090 * {@link EvictionPolicy} interface. 1091 */ 1092 public final void setEvictionPolicyClassName(final String evictionPolicyClassName, final ClassLoader classLoader) { 1093 // Getting epClass here and now best matches the caller's environment 1094 final Class<?> epClass = EvictionPolicy.class; 1095 final ClassLoader epClassLoader = epClass.getClassLoader(); 1096 try { 1097 try { 1098 setEvictionPolicy(evictionPolicyClassName, classLoader); 1099 } catch (final ClassCastException | ClassNotFoundException e) { 1100 setEvictionPolicy(evictionPolicyClassName, epClassLoader); 1101 } 1102 } catch (final ClassCastException e) { 1103 throw new IllegalArgumentException("Class " + evictionPolicyClassName + " from class loaders [" + 1104 classLoader + ", " + epClassLoader + "] do not implement " + EVICTION_POLICY_TYPE_NAME); 1105 } catch (final ClassNotFoundException | InstantiationException | IllegalAccessException | 1106 InvocationTargetException | NoSuchMethodException e) { 1107 final String exMessage = "Unable to create " + EVICTION_POLICY_TYPE_NAME + " instance of type " + 1108 evictionPolicyClassName; 1109 throw new IllegalArgumentException(exMessage, e); 1110 } 1111 } 1112 1113 /** 1114 * Sets the timeout that will be used when waiting for the Evictor to shutdown if this pool is closed and it is the 1115 * only pool still using the the value for the Evictor. 1116 * 1117 * @param evictorShutdownTimeoutMillis the timeout in milliseconds that will be used while waiting for the Evictor 1118 * to shut down. 1119 * @since 2.10.0 1120 */ 1121 public final void setEvictorShutdownTimeout(final Duration evictorShutdownTimeoutMillis) { 1122 this.evictorShutdownTimeout = evictorShutdownTimeoutMillis; 1123 } 1124 1125 /** 1126 * Sets the timeout that will be used when waiting for the Evictor to shutdown if this pool is closed and it is the 1127 * only pool still using the the value for the Evictor. 1128 * 1129 * @param evictorShutdownTimeoutMillis the timeout in milliseconds that will be used while waiting for the Evictor 1130 * to shut down. 1131 * @deprecated Use {@link #setEvictorShutdownTimeout(Duration)}. 1132 */ 1133 @Deprecated 1134 public final void setEvictorShutdownTimeoutMillis(final long evictorShutdownTimeoutMillis) { 1135 this.evictorShutdownTimeout = Duration.ofMillis(evictorShutdownTimeoutMillis); 1136 } 1137 1138 /** 1139 * Sets whether the pool has LIFO (last in, first out) behavior with 1140 * respect to idle objects - always returning the most recently used object 1141 * from the pool, or as a FIFO (first in, first out) queue, where the pool 1142 * always returns the oldest object in the idle object pool. 1143 * 1144 * @param lifo {@code true} if the pool is to be configured with LIFO 1145 * behavior or {@code false} if the pool is to be 1146 * configured with FIFO behavior 1147 * 1148 * @see #getLifo() 1149 */ 1150 public final void setLifo(final boolean lifo) { 1151 this.lifo = lifo; 1152 } 1153 1154 /** 1155 * Sets the cap on the number of objects that can be allocated by the pool 1156 * (checked out to clients, or idle awaiting checkout) at a given time. Use 1157 * a negative value for no limit. 1158 * 1159 * @param maxTotal The cap on the total number of object instances managed 1160 * by the pool. Negative values mean that there is no limit 1161 * to the number of objects allocated by the pool. 1162 * 1163 * @see #getMaxTotal 1164 */ 1165 public final void setMaxTotal(final int maxTotal) { 1166 this.maxTotal = maxTotal; 1167 } 1168 1169 /** 1170 * Sets the maximum amount of time (in milliseconds) the 1171 * {@code borrowObject()} method should block before throwing an 1172 * exception when the pool is exhausted and 1173 * {@link #getBlockWhenExhausted} is true. When less than 0, the 1174 * {@code borrowObject()} method may block indefinitely. 1175 * 1176 * @param maxWaitMillis the maximum number of milliseconds 1177 * {@code borrowObject()} will block or negative 1178 * for indefinitely. 1179 * 1180 * @see #getMaxWaitMillis 1181 * @see #setBlockWhenExhausted 1182 */ 1183 public final void setMaxWaitMillis(final long maxWaitMillis) { 1184 this.maxWait = Duration.ofMillis(maxWaitMillis); 1185 } 1186 1187 /** 1188 * Sets the minimum amount of time an object may sit idle in the pool 1189 * before it is eligible for eviction by the idle object evictor (if any - 1190 * see {@link #setTimeBetweenEvictionRuns(Duration)}). When non-positive, 1191 * no objects will be evicted from the pool due to idle time alone. 1192 * 1193 * @param minEvictableIdleTimeMillis 1194 * minimum amount of time an object may sit idle in the pool 1195 * before it is eligible for eviction 1196 * 1197 * @see #getMinEvictableIdleTime 1198 * @see #setTimeBetweenEvictionRuns 1199 * @since 2.10.0 1200 */ 1201 public final void setMinEvictableIdleTime(final Duration minEvictableIdleTimeMillis) { 1202 this.minEvictableIdleTime = minEvictableIdleTimeMillis; 1203 } 1204 1205 /** 1206 * Sets the minimum amount of time an object may sit idle in the pool 1207 * before it is eligible for eviction by the idle object evictor (if any - 1208 * see {@link #setTimeBetweenEvictionRunsMillis(long)}). When non-positive, 1209 * no objects will be evicted from the pool due to idle time alone. 1210 * 1211 * @param minEvictableIdleTimeMillis 1212 * minimum amount of time an object may sit idle in the pool 1213 * before it is eligible for eviction 1214 * 1215 * @see #getMinEvictableIdleTimeMillis 1216 * @see #setTimeBetweenEvictionRunsMillis 1217 * @deprecated Use {@link #setMinEvictableIdleTime(Duration)}. 1218 */ 1219 @Deprecated 1220 public final void setMinEvictableIdleTimeMillis(final long minEvictableIdleTimeMillis) { 1221 this.minEvictableIdleTime = Duration.ofMillis(minEvictableIdleTimeMillis); 1222 } 1223 1224 /** 1225 * Sets the maximum number of objects to examine during each run (if any) 1226 * of the idle object evictor thread. When positive, the number of tests 1227 * performed for a run will be the minimum of the configured value and the 1228 * number of idle instances in the pool. When negative, the number of tests 1229 * performed will be <code>ceil({@link #getNumIdle}/ 1230 * abs({@link #getNumTestsPerEvictionRun}))</code> which means that when the 1231 * value is {@code -n} roughly one nth of the idle objects will be 1232 * tested per run. 1233 * 1234 * @param numTestsPerEvictionRun 1235 * max number of objects to examine during each evictor run 1236 * 1237 * @see #getNumTestsPerEvictionRun 1238 * @see #setTimeBetweenEvictionRunsMillis 1239 */ 1240 public final void setNumTestsPerEvictionRun(final int numTestsPerEvictionRun) { 1241 this.numTestsPerEvictionRun = numTestsPerEvictionRun; 1242 } 1243 1244 /** 1245 * Sets the minimum amount of time an object may sit idle in the pool 1246 * before it is eligible for eviction by the idle object evictor (if any - 1247 * see {@link #setTimeBetweenEvictionRuns(Duration)}), 1248 * with the extra condition that at least {@code minIdle} object 1249 * instances remain in the pool. This setting is overridden by 1250 * {@link #getMinEvictableIdleTime} (that is, if 1251 * {@link #getMinEvictableIdleTime} is positive, then 1252 * {@link #getSoftMinEvictableIdleTime} is ignored). 1253 * 1254 * @param softMinEvictableIdleTime 1255 * minimum amount of time an object may sit idle in the pool 1256 * before it is eligible for eviction if minIdle instances are 1257 * available 1258 * 1259 * @see #getSoftMinEvictableIdleTimeMillis 1260 * @since 2.10.0 1261 */ 1262 public final void setSoftMinEvictableIdleTime(final Duration softMinEvictableIdleTime) { 1263 this.softMinEvictableIdleTime = softMinEvictableIdleTime; 1264 } 1265 1266 /** 1267 * Sets the minimum amount of time an object may sit idle in the pool 1268 * before it is eligible for eviction by the idle object evictor (if any - 1269 * see {@link #setTimeBetweenEvictionRunsMillis(long)}), 1270 * with the extra condition that at least {@code minIdle} object 1271 * instances remain in the pool. This setting is overridden by 1272 * {@link #getMinEvictableIdleTimeMillis} (that is, if 1273 * {@link #getMinEvictableIdleTimeMillis} is positive, then 1274 * {@link #getSoftMinEvictableIdleTimeMillis} is ignored). 1275 * 1276 * @param softMinEvictableIdleTimeMillis 1277 * minimum amount of time an object may sit idle in the pool 1278 * before it is eligible for eviction if minIdle instances are 1279 * available 1280 * 1281 * @see #getSoftMinEvictableIdleTimeMillis 1282 * @deprecated Use {@link #setSoftMinEvictableIdleTime(Duration)}. 1283 */ 1284 @Deprecated 1285 public final void setSoftMinEvictableIdleTimeMillis(final long softMinEvictableIdleTimeMillis) { 1286 this.softMinEvictableIdleTime = Duration.ofMillis(softMinEvictableIdleTimeMillis); 1287 } 1288 1289 /** 1290 * The listener used (if any) to receive notifications of exceptions 1291 * unavoidably swallowed by the pool. 1292 * 1293 * @param swallowedExceptionListener The listener or {@code null} 1294 * for no listener 1295 */ 1296 public final void setSwallowedExceptionListener( 1297 final SwallowedExceptionListener swallowedExceptionListener) { 1298 this.swallowedExceptionListener = swallowedExceptionListener; 1299 } 1300 1301 /** 1302 * Sets whether objects borrowed from the pool will be validated before 1303 * being returned from the {@code borrowObject()} method. Validation is 1304 * performed by the {@code validateObject()} method of the factory 1305 * associated with the pool. If the object fails to validate, it will be 1306 * removed from the pool and destroyed, and a new attempt will be made to 1307 * borrow an object from the pool. 1308 * 1309 * @param testOnBorrow {@code true} if objects should be validated 1310 * before being returned from the 1311 * {@code borrowObject()} method 1312 * 1313 * @see #getTestOnBorrow 1314 */ 1315 public final void setTestOnBorrow(final boolean testOnBorrow) { 1316 this.testOnBorrow = testOnBorrow; 1317 } 1318 1319 /** 1320 * Sets whether objects created for the pool will be validated before 1321 * being returned from the {@code borrowObject()} method. Validation is 1322 * performed by the {@code validateObject()} method of the factory 1323 * associated with the pool. If the object fails to validate, then 1324 * {@code borrowObject()} will fail. 1325 * 1326 * @param testOnCreate {@code true} if newly created objects should be 1327 * validated before being returned from the 1328 * {@code borrowObject()} method 1329 * 1330 * @see #getTestOnCreate 1331 * 1332 * @since 2.2 1333 */ 1334 public final void setTestOnCreate(final boolean testOnCreate) { 1335 this.testOnCreate = testOnCreate; 1336 } 1337 1338 /** 1339 * Sets whether objects borrowed from the pool will be validated when 1340 * they are returned to the pool via the {@code returnObject()} method. 1341 * Validation is performed by the {@code validateObject()} method of 1342 * the factory associated with the pool. Returning objects that fail validation 1343 * are destroyed rather then being returned the pool. 1344 * 1345 * @param testOnReturn {@code true} if objects are validated on 1346 * return to the pool via the 1347 * {@code returnObject()} method 1348 * 1349 * @see #getTestOnReturn 1350 */ 1351 public final void setTestOnReturn(final boolean testOnReturn) { 1352 this.testOnReturn = testOnReturn; 1353 } 1354 1355 /** 1356 * Sets whether objects sitting idle in the pool will be validated by the 1357 * idle object evictor (if any - see 1358 * {@link #setTimeBetweenEvictionRuns(Duration)}). Validation is performed 1359 * by the {@code validateObject()} method of the factory associated 1360 * with the pool. If the object fails to validate, it will be removed from 1361 * the pool and destroyed. Note that setting this property has no effect 1362 * unless the idle object evictor is enabled by setting 1363 * {@code timeBetweenEvictionRunsMillis} to a positive value. 1364 * 1365 * @param testWhileIdle 1366 * {@code true} so objects will be validated by the evictor 1367 * 1368 * @see #getTestWhileIdle 1369 * @see #setTimeBetweenEvictionRuns 1370 */ 1371 public final void setTestWhileIdle(final boolean testWhileIdle) { 1372 this.testWhileIdle = testWhileIdle; 1373 } 1374 1375 /** 1376 * Sets the number of milliseconds to sleep between runs of the idle object evictor thread. 1377 * <ul> 1378 * <li>When positive, the idle object evictor thread starts.</li> 1379 * <li>When non-positive, no idle object evictor thread runs.</li> 1380 * </ul> 1381 * 1382 * @param timeBetweenEvictionRuns 1383 * duration to sleep between evictor runs 1384 * 1385 * @see #getTimeBetweenEvictionRunsMillis 1386 * @since 2.10.0 1387 */ 1388 public final void setTimeBetweenEvictionRuns(final Duration timeBetweenEvictionRuns) { 1389 this.timeBetweenEvictionRuns = timeBetweenEvictionRuns; 1390 startEvictor(this.timeBetweenEvictionRuns); 1391 } 1392 1393 /** 1394 * Sets the number of milliseconds to sleep between runs of the idle object evictor thread. 1395 * <ul> 1396 * <li>When positive, the idle object evictor thread starts.</li> 1397 * <li>When non-positive, no idle object evictor thread runs.</li> 1398 * </ul> 1399 * 1400 * @param timeBetweenEvictionRunsMillis 1401 * number of milliseconds to sleep between evictor runs 1402 * 1403 * @see #getTimeBetweenEvictionRunsMillis 1404 * @deprecated Use {@link #setTimeBetweenEvictionRuns(Duration)}. 1405 */ 1406 @Deprecated 1407 public final void setTimeBetweenEvictionRunsMillis(final long timeBetweenEvictionRunsMillis) { 1408 this.timeBetweenEvictionRuns = Duration.ofMillis(timeBetweenEvictionRunsMillis); 1409 startEvictor(timeBetweenEvictionRuns); 1410 } 1411 1412 /** 1413 * <p>Starts the evictor with the given delay. If there is an evictor 1414 * running when this method is called, it is stopped and replaced with a 1415 * new evictor with the specified delay.</p> 1416 * 1417 * <p>This method needs to be final, since it is called from a constructor. 1418 * See POOL-195.</p> 1419 * 1420 * @param delay time in milliseconds before start and between eviction runs 1421 */ 1422 final void startEvictor(final Duration delay) { 1423 synchronized (evictionLock) { 1424 final boolean isPositiverDelay = PoolImplUtils.isPositive(delay); 1425 if (evictor == null) { // Starting evictor for the first time or after a cancel 1426 if (isPositiverDelay) { // Starting new evictor 1427 evictor = new Evictor(); 1428 EvictionTimer.schedule(evictor, delay, delay); 1429 } 1430 } else { // Stop or restart of existing evictor 1431 if (isPositiverDelay) { // Restart 1432 synchronized (EvictionTimer.class) { // Ensure no cancel can happen between cancel / schedule calls 1433 EvictionTimer.cancel(evictor, evictorShutdownTimeout, true); 1434 evictor = null; 1435 evictionIterator = null; 1436 evictor = new Evictor(); 1437 EvictionTimer.schedule(evictor, delay, delay); 1438 } 1439 } else { // Stopping evictor 1440 EvictionTimer.cancel(evictor, evictorShutdownTimeout, false); 1441 } 1442 } 1443 } 1444 } 1445 1446 1447 1448 // Inner classes 1449 1450 /** 1451 * Stops the evictor. 1452 */ 1453 void stopEvictor() { 1454 startEvictor(Duration.ofMillis(-1L)); 1455 } 1456 1457 /** 1458 * Swallows an exception and notifies the configured listener for swallowed 1459 * exceptions queue. 1460 * 1461 * @param swallowException exception to be swallowed 1462 */ 1463 final void swallowException(final Exception swallowException) { 1464 final SwallowedExceptionListener listener = getSwallowedExceptionListener(); 1465 1466 if (listener == null) { 1467 return; 1468 } 1469 1470 try { 1471 listener.onSwallowException(swallowException); 1472 } catch (final VirtualMachineError e) { 1473 throw e; 1474 } catch (final Throwable t) { 1475 // Ignore. Enjoy the irony. 1476 } 1477 } 1478 1479 @Override 1480 protected void toStringAppendFields(final StringBuilder builder) { 1481 builder.append("maxTotal="); 1482 builder.append(maxTotal); 1483 builder.append(", blockWhenExhausted="); 1484 builder.append(blockWhenExhausted); 1485 builder.append(", maxWaitMillis="); 1486 builder.append(maxWait); 1487 builder.append(", lifo="); 1488 builder.append(lifo); 1489 builder.append(", fairness="); 1490 builder.append(fairness); 1491 builder.append(", testOnCreate="); 1492 builder.append(testOnCreate); 1493 builder.append(", testOnBorrow="); 1494 builder.append(testOnBorrow); 1495 builder.append(", testOnReturn="); 1496 builder.append(testOnReturn); 1497 builder.append(", testWhileIdle="); 1498 builder.append(testWhileIdle); 1499 builder.append(", timeBetweenEvictionRunsMillis="); 1500 builder.append(timeBetweenEvictionRuns); 1501 builder.append(", numTestsPerEvictionRun="); 1502 builder.append(numTestsPerEvictionRun); 1503 builder.append(", minEvictableIdleTimeMillis="); 1504 builder.append(minEvictableIdleTime); 1505 builder.append(", softMinEvictableIdleTimeMillis="); 1506 builder.append(softMinEvictableIdleTime); 1507 builder.append(", evictionPolicy="); 1508 builder.append(evictionPolicy); 1509 builder.append(", closeLock="); 1510 builder.append(closeLock); 1511 builder.append(", closed="); 1512 builder.append(closed); 1513 builder.append(", evictionLock="); 1514 builder.append(evictionLock); 1515 builder.append(", evictor="); 1516 builder.append(evictor); 1517 builder.append(", evictionIterator="); 1518 builder.append(evictionIterator); 1519 builder.append(", factoryClassLoader="); 1520 builder.append(factoryClassLoader); 1521 builder.append(", oname="); 1522 builder.append(objectName); 1523 builder.append(", creationStackTrace="); 1524 builder.append(creationStackTrace); 1525 builder.append(", borrowedCount="); 1526 builder.append(borrowedCount); 1527 builder.append(", returnedCount="); 1528 builder.append(returnedCount); 1529 builder.append(", createdCount="); 1530 builder.append(createdCount); 1531 builder.append(", destroyedCount="); 1532 builder.append(destroyedCount); 1533 builder.append(", destroyedByEvictorCount="); 1534 builder.append(destroyedByEvictorCount); 1535 builder.append(", destroyedByBorrowValidationCount="); 1536 builder.append(destroyedByBorrowValidationCount); 1537 builder.append(", activeTimes="); 1538 builder.append(activeTimes); 1539 builder.append(", idleTimes="); 1540 builder.append(idleTimes); 1541 builder.append(", waitTimes="); 1542 builder.append(waitTimes); 1543 builder.append(", maxBorrowWaitTimeMillis="); 1544 builder.append(maxBorrowWaitTimeMillis); 1545 builder.append(", swallowedExceptionListener="); 1546 builder.append(swallowedExceptionListener); 1547 } 1548 1549 /** 1550 * Updates statistics after an object is borrowed from the pool. 1551 * 1552 * @param p object borrowed from the pool 1553 * @param waitTime time (in milliseconds) that the borrowing thread had to wait 1554 */ 1555 final void updateStatsBorrow(final PooledObject<T> p, final Duration waitTime) { 1556 borrowedCount.incrementAndGet(); 1557 idleTimes.add(p.getIdleTime()); 1558 waitTimes.add(waitTime); 1559 final long waitTimeMillis = waitTime.toMillis(); 1560 1561 // lock-free optimistic-locking maximum 1562 long currentMaxMillis; 1563 do { 1564 currentMaxMillis = maxBorrowWaitTimeMillis.get(); 1565 if (currentMaxMillis >= waitTimeMillis) { 1566 break; 1567 } 1568 } while (!maxBorrowWaitTimeMillis.compareAndSet(currentMaxMillis, waitTimeMillis)); 1569 } 1570 1571 /** 1572 * Updates statistics after an object is returned to the pool. 1573 * 1574 * @param activeTime the amount of time (in milliseconds) that the returning 1575 * object was checked out 1576 */ 1577 final void updateStatsReturn(final Duration activeTime) { 1578 returnedCount.incrementAndGet(); 1579 activeTimes.add(activeTime); 1580 } 1581 1582 1583}