code: @Override
      public String getToken() throws TokenManagerException {
          if (hasTokenExpired()) {
              synchronized (this) {
                  if (hasTokenExpired()) {
                      try {
                          final IAMToken iamToken = invokeTokenApi();
                          expiresAt = (long) (TimeUnit.SECONDS.toNanos(
                                  iamToken.expires_in) * tokenExpiryThreshold)
                                  + System.nanoTime();
                          token = iamToken.access_token;
                      } catch (final IAMTokenException e) {
                          throw new TokenManagerException("Failed getting Token.",
                                  e);
                      }
  
                  }
              }
          }
          return token;
      }
docs: Logic for getting token:<br>
  1. If has a valid token stored, send it.<br>
  2. If the stored token has expired, replace it with a new fetched token.<br>
  Note: This method is thread-safe and makes only one call to IAM API to replace an expired IAM token.