code: public static <T> Supplier<T> memoizeWithRandomExpiration(Supplier<T> delegate, long minDuration, long maxDuration, TimeUnit units) {
          if (minDuration == maxDuration) {
              // This case resolves to standard expiration
              return Suppliers.memoizeWithExpiration(delegate, minDuration, units);
          }
          return new RandomExpirationSupplier<T>(delegate, minDuration, maxDuration, units);
      }
docs: Memoization similar to {@link Suppliers#memoizeWithExpiration(Supplier, long, TimeUnit)} except the expiration
  is randomly selected to be a value within provided bounds.  For example:
  
  <code>
  Supplier&lt;Object&t; supplier = MoreSuppliers.memoizeWithRandomExpiration(delegate, 5, 10, TimeUnit.SECONDS);
  </code>
  
  returns a Supplier that will memoize the delegate's response for a random number of nanoseconds between 5
  (inclusive) to 10 (exclusive) seconds.
  
  This is useful when numerous memoized values are typically computed independently but used within the same operation.
  If all values were computed and memoized together then each call that refreshes from delegate could take longer
  than desirable.  Similarly, if each value were memomized independently using the same expiration then herding
  behavior would result in the same long calls at expiration time.  A random expiration allows each value to be
  cached but spread out the refresh cycle so that it is unlikely that any single call will refresh the entire value
  set, so long as the call frequency is significantly below <code>minDuration</code>.