package com.doke.utils;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.annotation.PreDestroy;
import java.util.Random;
import java.util.concurrent.*;
import java.util.function.Supplier;
/**
* TimeoutUtil <br>
*
* @author doker
* @date 2021/05/12
*/
@Slf4j
@Component
@NoArgsConstructor
public class ExecuteTimeoutUtil {
private final ExecutorService executorService = Executors.newFixedThreadPool(3);
@PreDestroy
private void destroy() {
executorService.shutdown();
}
/**
* 有超时限制的方法
*
* @param bizSupplier 业务函数
* @param timeout 超时时间,ms
* @return 返回值
*/
public <R> Result<R> executeTimeout(Supplier<R> bizSupplier, int timeout) {
return executeTimeout(bizSupplier, null, timeout);
}
/**
* 有超时限制的方法
*
* @param bizSupplier 业务函数
* @param defaultResult 默认值
* @param timeout 超时时间,ms
* @return 返回值
*/
public <R> Result<R> executeTimeout(Supplier<R> bizSupplier, R defaultResult, int timeout) {
R result;
String msg = "ok";
FutureTask<R> futureTask = new FutureTask<>(bizSupplier::get);
executorService.execute(futureTask);
try {
result = futureTask.get(timeout, TimeUnit.MILLISECONDS);
} catch (InterruptedException | ExecutionException | TimeoutException e) {
msg = String.format("execute time out %d ms force end", timeout);
log.error(msg, e);
futureTask.cancel(true);
result = defaultResult;
}
return of(result, msg);
}
/**
* 随机耗时的测试方法
*/
private String randomSpentTime() {
Random random = new Random();
int time = (random.nextInt(10) + 1) * 1000;
log.info("execute method expect spent time : " + time + "ms");
try {
Thread.sleep(time);
} catch (Exception e) {
}
return "randomSpentTime --> " + time;
}
public static void main(String[] args) throws Exception {
ExecuteTimeoutUtil executeTimeoutUtil = new ExecuteTimeoutUtil();
for (int i = 1; i <= 10; i++) {
log.info("\n sequence: {} time out", i);
Thread.sleep(6000);
long start = System.currentTimeMillis();
String result = executeTimeoutUtil.executeTimeout(() -> executeTimeoutUtil.randomSpentTime(), 5000).getOrElse("默认");
log.info("fact spend time {} ms,result:{}", System.currentTimeMillis() - start, result);
}
executeTimeoutUtil.executorService.shutdown();
}
class Result<T>{
private T data;
private String msg;
public Result(T data, String msg) {
this.data = data;
this.msg = msg;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public T getOrElse(T value) {
return this.data = value;
}
@Override
public String toString() {
return "Result{" +
"data=" + data +
", msg='" + msg + '\'' +
'}';
}
}
public <T> Result<T> of(T result, String msg) {
return new Result<>(result, msg);
}
}