通用的Java方法超时工具类

开发中执行耗时操作时,若规定时间内未完成则视为超时任务。Java的jdk1.5并发库中Future类可解决此问题,其重要方法有get()、cancel()和get(timeout)。还可利用泛型和函数式接口编写工具类,让超时处理更便捷。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

我们在开发过程中可能会遇到这样的场景:在执行一个耗时操作的时候,如果在规定的时间内处理完成了,则返回正确的结果,否则视为超时任务,这个时候我们将不再等待(不再执行)该耗时操作,直接告诉调用者:这个任务由于耗时过多,被取消了。

java早已经给我们提供了解决方案。jdk1.5自带的并发库中Future类就能满足这个需求。Future类中重要方法包括get()和cancel()。get()获取数据对象,如果数据没有加载,就会阻塞直到取到数据,而 cancel()是取消数据加载。另外一个get(timeout)操作,表示如果在timeout时间内没有取到就失败返回,而不再阻塞。 

利用泛型和函数式接口编写一个工具类,可以让超时处理更方便,而不用到处写代码。

/**
 * TimeoutUtil <br>
 *
 * @author lys
 * @date 2021/2/25
 */
@Slf4j
@Component
@NoArgsConstructor
public class TimeoutUtil {

    private ExecutorService executorService;

    public TimeoutUtil(ExecutorService executorService) {
        this.executorService = executorService;
    }

    /**
     * 有超时限制的方法
     *
     * @param bizSupplier 业务函数
     * @param timeout     超时时间,ms
     * @return 返回值
     */
    public <R> Result<R> doWithTimeLimit(Supplier<R> bizSupplier, int timeout) {
        return doWithTimeLimit(bizSupplier, null, timeout);
    }

    /**
     * 有超时限制的方法
     *
     * @param bizSupplier   业务函数
     * @param defaultResult 默认值
     * @param timeout       超时时间,ms
     * @return 返回值
     */
    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执行超过%d毫秒,强制结束", timeout);
            log.error(errMsg, e);
            futureTask.cancel(true);
            result = defaultResult;
        }
        return of(result, errMsg);
    }

    /**
     * 随机耗时的测试方法
     */
    private String randomSpentTime() {
        Random random = new Random();
        int time = (random.nextInt(10) + 1) * 1000;
        log.info("预计randomSpentTime方法执行将耗时: " + time + "毫秒");
        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);
                    // 以守护线程方式启动
                    thread.setDaemon(true);
                    return thread;
                });
        TimeoutUtil timeoutUtil = new TimeoutUtil(executorService);
        for (int i = 1; i <= 10; i++) {
            log.info("\n=============第{}次超时测试=============", i);
            Thread.sleep(6000);
            long start = System.currentTimeMillis();
            String result = timeoutUtil.doWithTimeLimit(() -> timeoutUtil.randomSpentTime(), 5000).getOrElse("默认");
            log.info("doWithTimeLimit方法实际耗时{}毫秒,结果:{}", System.currentTimeMillis() - start, result);
        }
    }

}

测结果如下:

Result是一套函数式的返回值包装类,参考《Java函数式编程》


import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.apache.commons.lang.StringUtils;
import org.springframework.util.CollectionUtils;

import java.io.Serializable;
import java.util.Collection;
import java.util.function.Function;
import java.util.function.Supplier;

/**
 * Result接口表示函数调用的结果
 *
 * @author lys
 * @date 2020/06/08
 * @since 1.0.0
 */
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public abstract class Result<V> implements Serializable {

    /**
     * serialVersionUID
     */
    private static final long serialVersionUID = -8917987013371280396L;

    /**
     * 单例的empty对象,表示空
     */
    private static final Result EMPTY = new Empty<>();

    /**
     * 单例的failure对象,表示null
     */
    private static final Result FAILURE_NULL = failure("Null value");

    //==================================静态方法Start==================================

    /**
     * 返回成功子类对象
     *
     * @param value 返回值
     * @param <V>   返回值类型
     * @return
     */
    public static <V> Result<V> success(V value) {
        return new Success<>(value);
    }

    /**
     * 返回为空子类对象
     *
     * @param <V> 返回值类型
     * @return
     */
    public static <V> Result<V> empty() {
        return EMPTY;
    }

    public static <V, U> Result<V> failure(Failure<U> failure) {
        return new Failure<>(failure.exception);
    }

    /**
     * 返回失败子类对象
     *
     * @param errMsg 错误信息
     * @param <V>    返回值类型
     * @return
     */
    public static <V> Result<V> failure(String errMsg) {
        return new Failure<>(errMsg);
    }

    /**
     * 返回失败子类对象
     *
     * @param ex  失败异常
     * @param <V> 返回值类型
     * @return
     */
    public static <V> Result<V> failure(Exception ex) {
        return new Failure<>(ex);
    }

    /**
     * 返回失败子类对象
     *
     * @param ex  失败运行时异常
     * @param <V> 返回值类型
     * @return
     */
    public static <V> Result<V> failure(RuntimeException ex) {
        return new Failure<>(ex);
    }

    /**
     * of工厂方法
     *
     * @param value
     * @param <V>
     * @return Result&lt;V&gt;
     */
    public static <V> Result<V> of(V value) {
        return value != null ?
                success(value) : FAILURE_NULL;
    }
   
    /**
     * of工厂方法
     *
     * @param value
     * @param errMsg 错误信息
     * @param <V>
     * @return Result&lt;V&gt;
     */
    public static <V> Result<V> of(V value, String errMsg) {
        return value != null ?
                success(value) : failure(errMsg);
    }

    /**
     * 获得调用结果或默认值
     *
     * @param defaultValue 默认值
     * @return
     */
    public abstract V getOrElse(final V defaultValue);

    //==================================静态方法End==================================

    //==================================抽象方法Start==================================

    /**
     * 获得调用结果或默认值
     *
     * @param defaultValue 默认值Supplier
     * @return
     */
    public abstract V getOrElse(final Supplier<V> defaultValue);

    /**
     * map方法通过应用从V到U的函数将Result&lt;V&gt;更改为Result&lt;U&gt;
     *
     * @param f 从V到U的函数
     * @return Result&lt;U&gt;
     */
    public abstract <U> Result<U> map(final Function<V, U> f);

    /**
     * flatMap方法通过应用从V到Result&lt;U&gt;的函数将Result&lt;V&gt;更改为Result&lt;U&gt;
     *
     * @param f 从V到Result&lt;U&gt;的函数
     * @return Result&lt;U&gt;
     */
    public abstract <U> Result<U> flatMap(final Function<V, Result<U>> f);

    /**
     * 失败映射方法<br>
     * 以String为参数,并以其为错误消息将一个Failure转换为另一个Failure,如果Result为Empty或Success只返回this
     * @param s
     * @return
     */
    public abstract Result<V> mapFailure(String s);

    /**
     * 针对Empty的映射
     *
     * @return 当前对象为Empty时入返回success对象,否则返回failure
     */
    public abstract Result<Nothing> mapEmpty();

    /**
     * 以String为参数,并以其为错误消息将一个Empty转换为一个Failure;
     * 如果Result为Failure则以输入字符串为错误消息转换为另一个Failure;
     * 如果Result为Success只返回this。<br>
     * @param message 错误消息
     * @return
     */
    public abstract Result<V> failIfEmpty(String message);

    /**
     * forEach方法,以一个Effect为参数,并将其应用于包装值
     *
     * @param ef 函数作用,用于对包装值执行具体的业务逻辑
     * @return
     */
    public abstract void forEach(Effect<V> ef);

    /**
     * 判断是否为成功结果
     * @return 是否为成功结果标识
     */
    public abstract Boolean isSuccess();

    /**
     * 判断是否为失败结果
     * @return 是否为失败结果标识
     */
    public abstract Boolean isFailure();

    /**
     * 判断是否为空结果
     * @return 是否为空结果标识
     */
    public abstract Boolean isEmpty();

    //==================================抽象方法End==================================

    //==================================非抽象方法Start==================================

    /**
     * 从Result&lt;V&gt;中检索值,为空返回默认值
     *
     * @return
     */
    public Result<V> orElse(Supplier<Result<V>> defaultValue) {
        return map(x -> this).getOrElse(defaultValue);
    }

    //==================================非抽象方法End==================================

    //==================================子类实现Start==================================
    /**
     * 表示为空结果
     */
    private static class Empty<V> extends Result<V> {

        private static final long serialVersionUID = 5115067706362088704L;

        private Empty() {
            super();
        }

        @Override
        public V getOrElse(V defaultValue) {
            return defaultValue;
        }

        @Override
        public <U> Result<U> map(Function<V, U> f) {
            return empty();
        }

        @Override
        public <U> Result<U> flatMap(Function<V, Result<U>> f) {
            return empty();
        }

        /**
         * 以String为参数,并以其为错误消息将一个Failure转换为另一个Failure,如果Result为Empty或Success只返回this
         *
         * @param s 错误消息
         * @return
         */
        @Override
        public Result<V> mapFailure(String s) {
            return this;
        }

        @Override
        public Result<V> mapFailure(Function<Exception, Exception> exConvertor) {
            return this;
        }

        /**
         * 针对Empty的映射
         *
         * @return 当前对象为Empty时入返回success对象,否则返回failure
         */
        @Override
        public Result<Nothing> mapEmpty() {
            return success(Nothing.INSTANCE);
        }

        /**
         * 以String为参数,并以其为错误消息将一个Empty转换为一个Failure;
         * 如果Result为Failure则以输入字符串为错误消息转换为另一个Failure;
         * 如果Result为Success只返回this。<br>
         *
         * @param message 错误消息
         * @return
         */
        @Override
        public Result<V> failIfEmpty(String message) {
            return failure(message);
        }

        /**
         * forEach方法,以一个Effect为参数,并将其应用于包装值
         *
         * @param ef 函数作用,用于对包装值执行具体的业务逻辑
         * @return
         */
        @Override
        public void forEach(Effect<V> ef) {
            // Empty. Do nothing
        }

        /**
         * 判断是否为成功结果
         *
         * @return 是否为成功结果标识
         */
        @Override
        public Boolean isSuccess() {
            return false;
        }

        /**
         * 判断是否为失败结果
         *
         * @return 是否为失败结果标识
         */
        @Override
        public Boolean isFailure() {
            return false;
        }

        /**
         * 判断是否为空结果
         *
         * @return 是否为空结果标识
         */
        @Override
        public Boolean isEmpty() {
            return true;
        }

        @Override
        public String toString() {
            return "Empty()";
        }

    }

    /**
     * 表示成功结果
     */
    private static class Success<V> extends Result<V> {

        /**
         * serialVersionUID
         */
        private static final long serialVersionUID = 633612507243796152L;

        private final V value;

        private Success(V value) {
            super();
            this.value = value;
        }

        @Override
        public String toString() {
            return String.format("Success(%s)", value != null ? value.toString() : null);
        }

        /**
         * 获得调用结果或默认值
         *
         * @param defaultValue 默认值
         * @return
         */
        @Override
        public V getOrElse(V defaultValue) {
            return value;
        }

        /**
         * map方法通过应用从V到U的函数将Result&lt;V&gt;更改为Result&lt;U&gt;
         *
         * @param f 从V到U的函数
         * @return Result&lt;U&gt;
         */
        @Override
        public <U> Result<U> map(Function<V, U> f) {
            try {
                return success(f.apply(value));
            } catch (Exception e) {
                return failure(e);
            }
        }

        /**
         * flatMap方法通过应用从V到Result&lt;U&gt;的函数将Result&lt;V&gt;更改为Result&lt;U&gt;
         *
         * @param f 从V到Result&lt;U&gt;的函数
         * @return Result&lt;U&gt;
         */
        @Override
        public <U> Result<U> flatMap(Function<V, Result<U>> f) {
            try {
                return f.apply(value);
            } catch (Exception e) {
                return failure(e);
            }
        }

        /**
         * 以String为参数,并以其为错误消息将一个Failure转换为另一个Failure,如果Result为Empty或Success只返回this
         *
         * @param s 错误消息
         * @return
         */
        @Override
        public Result<V> mapFailure(String s) {
            return this;
        }

        /**
         * 针对Empty的映射
         *
         * @return 当前对象为Empty时入返回success对象,否则返回failure
         */
        @Override
        public Result<Nothing> mapEmpty() {
            return failure("Not empty");
        }

        /**
         * 以String为参数,并以其为错误消息将一个Empty转换为一个Failure;
         * 如果Result为Failure则以输入字符串为错误消息转换为另一个Failure;
         * 如果Result为Success只返回this。<br>
         *
         * @param message 错误消息
         * @return
         */
        @Override
        public Result<V> failIfEmpty(String message) {
            return this;
        }

        /**
         * forEach方法,以一个Effect为参数,并将其应用于包装值
         *
         * @param ef 函数作用,用于对包装值执行具体的业务逻辑
         * @return
         */
        @Override
        public void forEach(Effect<V> ef) {
            ef.apply(value);
        }
		
        /**
         * 判断是否为成功结果
         *
         * @return 是否为成功结果标识
         */
        @Override
        public Boolean isSuccess() {
            return true;
        }

        /**
         * 判断是否为失败结果
         *
         * @return 是否为失败结果标识
         */
        @Override
        public Boolean isFailure() {
            return false;
        }

        /**
         * 判断是否为空结果
         *
         * @return 是否为空结果标识
         */
        @Override
        public Boolean isEmpty() {
            return false;
        }
    }

    /**
     * 表示失败结果
     */
    private static class Failure<V> extends Empty<V> {

        /**
         * serialVersionUID
         */
        private static final long serialVersionUID = 4991495838920816791L;

        private final RuntimeException exception;

        /**
         * 构造函数
         *
         * @param errMsg 错误信息
         */
        private Failure(String errMsg) {
            super();
            this.exception = new IllegalStateException(errMsg);
        }

        private Failure(Exception exception) {
            super();
            this.exception = new IllegalStateException(exception.getMessage(), exception);
        }

        @Override
        public String toString() {
            return String.format("Failure(%s)", exception.getMessage());
        }

        /**
         * map方法通过应用从V到U的函数将Result&lt;V&gt;更改为Result&lt;U&gt;
         *
         * @param f 从V到U的函数
         * @return Result&lt;U&gt;
         */
        @Override
        public <U> Result<U> map(Function<V, U> f) {
            return failure(exception);
        }

        /**
         * flatMap方法通过应用从V到Result&lt;U&gt;的函数将Result&lt;V&gt;更改为Result&lt;U&gt;
         *
         * @param f 从V到Result&lt;U&gt;的函数
         * @return Result&lt;U&gt;
         */
        @Override
        public <U> Result<U> flatMap(Function<V, Result<U>> f) {
            return failure(exception);
        }

        /**
         * 针对Empty的映射
         *
         * @return 当前对象为Empty时入返回success对象,否则返回failure
         */
        @Override
        public Result<Nothing> mapEmpty() {
            return failure(this);
        }

        /**
         * 判断是否为失败结果
         *
         * @return 是否为失败结果标识
         */
        @Override
        public Boolean isFailure() {
            return true;
        }
    }

    //==================================子类实现End==================================
}

参考:http://blog.youkuaiyun.com/a1015088819/article/details/53099943

https://blog.youkuaiyun.com/ithouse/article/details/78257418

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值