Explanation of writing timeout tool class example in Java

  • 2021-08-31 07:43:25
  • OfStack

We in the development process, in the time operation, if in the specified time to complete the processing, it is possible to return to the correct results. Otherwise, it will be regarded as a timeout task. At this point, we no longer wait (no longer execute) the time operation, and directly communicate to the caller that this task takes time and is cancelled.

1. Description

java has provided us with a solution. The concurrency library Future class that comes with jdk 1.5 meets this 1 requirement. Important methods in the Future class are get () and cancel (). get () fetches the data object. If the data is not loaded, it blocks before fetching the data. cancel () cancels the data loading. Another get (timeout) operation shows that if timeout is not available, it will fail back and will not be blocked.

Using generic and functional interfaces to write a tool class can make timeout processing more convenient without writing code everywhere.

2. Examples


/**
 * TimeoutUtil <br>
 *
 * @author lys
 * @date 2021/2/25
 */

@Slf4j
@Component
@NoArgsConstructor
public class TimeoutUtil {
 private ExecutorService executorService;
 public TimeoutUtil(ExecutorService executorService) {
   this.executorService = executorService;
 }

 /**
  *  Method with timeout limit 
  *
  * @param bizSupplier  Business function 
  * @param timeout    Timeout, ms
  * @return  Return value 
  */
 public <R> Result<R> doWithTimeLimit(Supplier<R> bizSupplier, int timeout) {
   return doWithTimeLimit(bizSupplier, null, timeout);
 }

 /**
  *  Method with timeout limit 
  *
  * @param bizSupplier   Business function 
  * @param defaultResult  Default value 
  * @param timeout     Timeout, ms
  * @return  Return value 
  */
 public <R> Result<R> doWithTimeLimit(Supplier<R> bizSupplier, R defaultResult, int timeout) {

   R result;
   String errMsg = "Null value";
   FutureTask<R> futureTask = new FutureTask<>(bizSupplier::get);
   executorService.execute(futureTask);
   try {
     result = futureTask.get(timeout, TimeUnit.MILLISECONDS);
   } catch (InterruptedException | ExecutionException | TimeoutException e) {
     errMsg = String.format("doWithTimeLimit Execute more than %d Milliseconds, forced end ", timeout);
     log.error(errMsg, e);
     futureTask.cancel(true);
     result = defaultResult;
   }
   return of(result, errMsg);
 }

 /**
  *  Random time-consuming test method 
  */
 private String randomSpentTime() {
   Random random = new Random();
   int time = (random.nextInt(10) + 1) * 1000;
   log.info(" Anticipate randomSpentTime Method execution will take time:  " + time + " Milliseconds ");
   try {
     Thread.sleep(time);
   } catch (Exception e) {
   }
   return "randomSpentTime --> " + time;
 }

 public static void main(String[] args) throws Exception {
   ExecutorService executorService = new ThreadPoolExecutor(1, 1,
       0L, TimeUnit.MILLISECONDS,
       new LinkedBlockingQueue<Runnable>(),
       runnable -> {
         Thread thread = new Thread(runnable);
         //  Start as a daemon thread 
         thread.setDaemon(true);
         return thread;
       });
   TimeoutUtil timeoutUtil = new TimeoutUtil(executorService);
   for (int i = 1; i <= 10; i++) {
     log.info("\n============= No. 1 {} Second timeout test =============", i);
     Thread.sleep(6000);
     long start = System.currentTimeMillis();
     String result = timeoutUtil.doWithTimeLimit(() -> timeoutUtil.randomSpentTime(), 5000).getOrElse(" Default ");
     log.info("doWithTimeLimit Actual time consuming of method {} Milliseconds, result: {}", System.currentTimeMillis() - start, result);
   }
 }


}

Extension of instance knowledge points:

Attribute validation tool class


/**
   *  Verify the properties in the object. If the property is null, Throw an exception. If the property is a string (empty string or space), throw an exception. 
   * @author mex
   * @date 2019 Year 4 Month 18 Day 
   * @param e  Object 
   * @param fieldNames  Attribute name array 
   * @return void
   * @throws Exception
   */
  public static <E> void validateAttr(E e, String[] fieldNames) throws Exception {
    if (null == e) {
      throw new Exception(" Request object is empty ");
    }
    if (null == fieldNames) {
      return;
    }
    for (int i = 0; i < fieldNames.length; i++) {
      String fieldName = fieldNames[i];
      Field field = e.getClass().getDeclaredField(fieldName);
      String typeName = field.getGenericType().getTypeName();
      field.setAccessible(Boolean.TRUE);
      Object fieldValue = field.get(e);
      //  Determine that the attribute is null The situation of 
      if (null == fieldValue) {
        throw new Exception(" Request field: " + fieldName + " Cannot be empty ");
      }
      //  If the attribute is a string, determine whether it is empty or empty 
      if ("java.lang.String".equals(typeName)) {
        if (StringUtils.isBlank((String)fieldValue)) {
          throw new Exception(" Request field: " + fieldName + " Cannot be empty ");
        }
      }
    }
  }

Related articles: