All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.cp.elements.lang.RunnableUtils Maven / Gradle / Ivy

/*
 * Copyright 2011-Present Author or Authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.cp.elements.lang;

import java.util.Optional;

import org.cp.elements.lang.concurrent.ThreadUtils;

/**
 * Abstract utility class used to process {@link Runnable objects}.
 *
 * @author John Blum
 * @see java.lang.Runnable
 * @see org.cp.elements.lang.concurrent.ThreadUtils
 * @since 1.0.0
 */
@SuppressWarnings("unused")
public abstract class RunnableUtils {

  public static final Runnable NOOP_RUNNABLE = () -> { };

  /**
   * Runs the given {@link Runnable} object and then causes the current, calling {@link Thread} to sleep
   * for the given number of milliseconds.
   *
   * This utility method can be used to simulate a long running, expensive operation.
   *
   * @param milliseconds a long value with the number of milliseconds for the current {@link Thread} to sleep.
   * @param runnable {@link Runnable} object to run; must not be {@literal null}.
   * @return a boolean value indicating whether the {@link Runnable} ran successfully
   * and whether the current {@link Thread} slept for the given number of milliseconds.
   * @throws IllegalArgumentException if milliseconds is less than equal to 0.
   * @see org.cp.elements.lang.concurrent.ThreadUtils#sleep(long, int)
   * @see java.lang.Runnable#run()
   */
  public static boolean runWithSleep(long milliseconds, Runnable runnable) {

    Assert.isTrue(milliseconds > 0, "Milliseconds [%d] must be greater than 0", milliseconds);

    runnable.run();

    return ThreadUtils.sleep(milliseconds, 0);
  }

  /**
   * Runs the given {@link Runnable} object and then causes the current, calling {@link Thread} to sleep
   * for the given number of milliseconds.
   *
   * This utility method can be used to simulate a long running, expensive operation.
   *
   * @param milliseconds a long value with the number of milliseconds for the current {@link Thread} to sleep.
   * @param runnable {@link Runnable} object to run; must not be {@literal null}.
   * @return a boolean value indicating whether the {@link Runnable} ran successfully
   * and whether the current {@link Thread} slept for the given number of milliseconds.
   * @throws IllegalArgumentException if milliseconds is less than equal to 0.
   * @throws SleepDeprivedException if the current {@link Thread} is interrupted while sleeping.
   * @see org.cp.elements.lang.concurrent.ThreadUtils#sleep(long, int)
   * @see java.lang.Runnable#run()
   */
  public static boolean runWithSleepThrowOnInterrupt(long milliseconds, Runnable runnable) {

    Assert.isTrue(milliseconds > 0, "Milliseconds [%d] must be greater than 0", milliseconds);

    runnable.run();

    if (!ThreadUtils.sleep(milliseconds, 0)) {
      throw new SleepDeprivedException(String.format("Failed to wait for [%d] millisecond(s)", milliseconds));
    }

    return true;
  }

  /**
   * Runs the given {@link Runnable} object and then causes the current, calling {@link Thread} to sleep
   * for the given number of milliseconds.
   *
   * This utility method sleeps uninterrupted, resetting the interrupt bit if the current, calling {@link Thread}
   * is interrupted during sleep.
   *
   * This utility method can be used to simulate a long running, expensive operation.
   *
   * @param milliseconds a long value with the number of milliseconds for the current {@link Thread} to sleep.
   * @param runnable {@link Runnable} object to run; must not be {@literal null}.
   * @return a boolean value indicating whether the {@link Runnable} ran successfully
   * and whether the current {@link Thread} slept for the given number of milliseconds.
   * @throws IllegalArgumentException if milliseconds is less than equal to 0.
   * @see java.lang.Runnable#run()
   * @see #safeSleep(long)
   */
  public static boolean runWithSleepUninterrupted(long milliseconds, Runnable runnable) {

    Assert.isTrue(milliseconds > 0, "Milliseconds [%d] must be greater than 0", milliseconds);

    runnable.run();

    return safeSleep(milliseconds);
  }

  /**
   * Runs the given {@link ReturningRunnable} object and then causes the current, calling {@link Thread} to sleep
   * for the given number of milliseconds before returning a value.
   *
   * This utility method can be used to simulate a long running, expensive operation.
   *
   * @param  {{@link Class} type of the {@link ReturningRunnable} return value.
   * @param milliseconds a long value with the number of milliseconds for the current {@link Thread} to sleep.
   * @param runnable {@link ReturningRunnable} object to run; must not be {@literal null}.
   * @return the value returned by the {@link ReturningRunnable}.
   * @throws IllegalArgumentException if milliseconds is less than equal to 0.
   * @see org.cp.elements.lang.RunnableUtils.ReturningRunnable#run()
   * @see org.cp.elements.lang.concurrent.ThreadUtils#sleep(long, int)
   */
  public static  T runWithSleepThenReturnValue(long milliseconds, ReturningRunnable runnable) {

    Assert.isTrue(milliseconds > 0, "Milliseconds [%d] must be greater than 0", milliseconds);

    T returnValue = runnable.run();

    ThreadUtils.sleep(milliseconds, 0);

    return returnValue;
  }

  /**
   * Runs the given {@link ReturningRunnable} object and then causes the current, calling {@link Thread} to sleep
   * for the given number of milliseconds before returning a value.
   *
   * This utility method can be used to simulate a long running, expensive operation.
   *
   * @param  {{@link Class} type of the {@link ReturningRunnable} return value.
   * @param milliseconds a long value with the number of milliseconds for the current {@link Thread} to sleep.
   * @param runnable {@link ReturningRunnable} object to run; must not be {@literal null}.
   * @return the value returned by the {@link ReturningRunnable}.
   * @throws IllegalArgumentException if milliseconds is less than equal to 0.
   * @throws SleepDeprivedException if the current {@link Thread} is interrupted while sleeping.
   * @see org.cp.elements.lang.RunnableUtils.ReturningRunnable#run()
   * @see org.cp.elements.lang.concurrent.ThreadUtils#sleep(long, int)
   */
  public static  T runWithSleepThenReturnValueThrowOnInterrupt(long milliseconds, ReturningRunnable runnable) {

    Assert.isTrue(milliseconds > 0, "Milliseconds [%d] must be greater than 0", milliseconds);

    T returnValue = runnable.run();

    if (!ThreadUtils.sleep(milliseconds, 0)) {
      throw new SleepDeprivedException(String.format("Failed to wait for [%d] millisecond(s)", milliseconds));
    }

    return returnValue;
  }

  /**
   * Runs the given {@link ReturningRunnable} object and then causes the current, calling {@link Thread} to sleep
   * for the given number of milliseconds before returning a value.
   *
   * This utility method sleeps uninterrupted, resetting the interrupt bit if the current, calling {@link Thread}
   * is interrupted during sleep.
   *
   * This utility method can be used to simulate a long running, expensive operation.
   *
   * @param  {{@link Class} type of the {@link ReturningRunnable} return value.
   * @param milliseconds a long value with the number of milliseconds for the current {@link Thread} to sleep.
   * @param runnable {@link ReturningRunnable} object to run; must not be {@literal null}.
   * @return the value returned by the {@link ReturningRunnable}.
   * @throws IllegalArgumentException if milliseconds is less than equal to 0.
   * @see org.cp.elements.lang.RunnableUtils.ReturningRunnable#run()
   * @see #safeSleep(long)
   */
  public static  T runWithSleepThenReturnValueUninterrupted(long milliseconds, ReturningRunnable runnable) {

    Assert.isTrue(milliseconds > 0, "Milliseconds [%d] must be greater than 0", milliseconds);

    T returnValue = runnable.run();

    safeSleep(milliseconds);

    return returnValue;
  }

  /**
   * Safely sleeps for the given amount of milliseconds.
   *
   * If the {@link Thread#currentThread() current Thread} is {@link Thread#isInterrupted() interrupted} while
   * {@link Thread#sleep(long, int) sleeping}, then the {@link Thread#currentThread() current Thread} will continue
   * to {@link Thread#sleep(long, int) sleep} until the given number of milliseconds have expired and the interrupt bit
   * will be set on return.
   *
   * @param milliseconds the number of milliseconds that the {@link Thread#currentThread() current Thread} will sleep.
   * @return {@literal true} if the {@link Thread#currentThread() current Thread} was able to
   * {@link Thread#sleep(long, int)} for the given number of milliseconds uninterrupted.
   * @see java.lang.Thread#sleep(long, int)
   */
  @SuppressWarnings("all")
  private static boolean safeSleep(long milliseconds) {

    boolean interrupted = false;

    long remainingMilliseconds = milliseconds;
    long timeout = System.currentTimeMillis() + milliseconds;

    while (System.currentTimeMillis() < timeout) {
      try {
        Thread.sleep(remainingMilliseconds);
      }
      catch (InterruptedException cause) {
        interrupted = true;
      }
      finally {
        remainingMilliseconds = Math.min(timeout - System.currentTimeMillis(), 0);
      }
    }

    if (interrupted) {
      Thread.currentThread().interrupt();
    }

    return !Thread.currentThread().isInterrupted();
  }

  /**
   * Times the {@link Runnable#run()} method of the given {@link Runnable}.
   *
   * @param runnable the {@link Runnable} object to run and time.
   * @return the amount of time in milliseconds that it took to run the given {@link Runnable}.
   * @see java.lang.Runnable
   */
  public static Optional timedRun(Runnable runnable) {
    long t0 = System.currentTimeMillis();
    runnable.run();
    return Optional.of(System.currentTimeMillis() - t0);
  }

  /**
   * The {@link ReturningRunnable} interface defines a contract for implementing objects that run a computation
   * and return a value.
   *
   * @param  {@link Class} type of the return value.
   */
  @FunctionalInterface
  public interface ReturningRunnable {

    /**
     * Computation to run.
     *
     * @return the result of the computation.
     */
    T run();

  }

  /**
   * The {@link SleepDeprivedException} is a {@link RuntimeException} that is thrown when a {@link Thread}
   * did not get all of its {@link Thread#sleep(long, int) sleep}.
   *
   * @see java.lang.RuntimeException
   */
  public static final class SleepDeprivedException extends RuntimeException {

    /**
     * Construct a new instance of the {@link SleepDeprivedException} with no {@link String message} or no known
     * {@link Throwable cause}.
     */
    public SleepDeprivedException() {
    }

    /**
     * Construct a new instance of the {@link SleepDeprivedException} initialized with given {@link String message}
     * describing the reason for this exception.
     *
     * @param message {@link String} describing the reason for this exception.
     */
    public SleepDeprivedException(String message) {
      super(message);
    }

    /**
     * Construct a new instance of the {@link SleepDeprivedException} initialized with given {@link Throwable cause}
     * of this exception.
     *
     * @param cause {@link Throwable} object as the underlying cause of this exception.
     * @see java.lang.Throwable
     */
    public SleepDeprivedException(Throwable cause) {
      super(cause);
    }

    /**
     * Construct a new instance of the {@link SleepDeprivedException} initialized with given {@link String message}
     * describing the reason for this exception along with the underlying {@link Throwable cause} of this exception.
     *
     * @param message {@link String} describing the reason for this exception.
     * @param cause {@link Throwable} object as the underlying cause of this exception.
     * @see java.lang.Throwable
     */
    public SleepDeprivedException(String message, Throwable cause) {
      super(message, cause);
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy