指数退避算法+异步任务

参考:https://www.jianshu.com/p/0a6ee8c13522

指数退避的原理是对于连续错误响应,重试等待间隔越来越长。
您应该实施最长延迟间隔和最大重试次数。最长延迟间隔和最大重试次数不一定是固定值,并且应当根据正在执行的操作和其他本地因素(例如网络延迟)进行设置。
大多数指数退避算法会利用抖动(随机延迟)来防止连续的冲突。

由于在这些情况下您并未尝试避免此类冲突,因此无需使用此随机数字。但是,如果使用并发客户端,抖动可帮助您更快地成功执行请求

1 配置异步线程池

package cn.shu.zhishutuibi;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.TaskExecutor;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.ThreadPoolExecutor;

@Configuration
@EnableAsync
public class BeanConfig {

    /*配置一个线程池*/
    @Bean
    public TaskExecutor taskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        // 设置核心线程数
        executor.setCorePoolSize(4);
        // 设置最大线程数
        executor.setMaxPoolSize(4);
        // 设置队列容量
        executor.setQueueCapacity(4);
        // 设置线程活跃时间(秒)
        executor.setKeepAliveSeconds(60);
        // 设置默认线程名称
        executor.setThreadNamePrefix("itsm-");
        // 设置拒绝策略
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        // 等待所有任务结束后再关闭线程池
        executor.setWaitForTasksToCompleteOnShutdown(true);
        return executor;
    }
}

2 写一个Conreoller

@GetMapping("/asynctest")
public String asynctest() {
    System.out.println("asynctest方法开始"+new Date());
    task.doTaskOne();
    System.out.println("asynctest方法结束"+new Date());
    return "访问成功";
}

3写一个任务类

package cn.shu.zhishutuibi;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import java.util.*;

/*
 * 配置任务*/
@Component
public class Task {
    private static final org.slf4j.Logger logger = LoggerFactory.getLogger(Task.class);

    private static Random random = new Random();

    //最大重试次数
    public static int MAX_RETRIES = 4;
    //最大重试间隔  5分钟
    public static long MAX_WAIT_INTERVAL = 1000L * 60 * 5;


   /* @Async
    public void doTaskOne() throws Exception {
        System.out.println("开始做任务一");
        long start = System.currentTimeMillis();
        Thread.sleep(random.nextInt(10000));
        long end = System.currentTimeMillis();
        System.out.println("完成任务一,耗时:" + (end - start) + "毫秒");
    }*/

    @Async
    public void doTaskOne() {
        System.out.println(Thread.currentThread().getName() + "开始做任务一");
        logger.info(Thread.currentThread().getName() + "开始做任务一");
        long start = System.currentTimeMillis();

        // Do some asynchronous operation.
//            long token = asyncOperation();
        int retries = 0;
        boolean retry = false;
        System.out.println("开始执行getAsyncOperationResult");
        logger.info("开始执行getAsyncOperationResult");
        Results result = getAsyncOperationResult();
        System.out.println("结束执行getAsyncOperationResult:" + result);
        logger.info("结束执行getAsyncOperationResult:" + result);
        if (Results.Retry == result) {
            try {
                Thread.sleep(1000L * 60);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            do {
                long waitTime = Math.min(getWaitTimeExp(retries), MAX_WAIT_INTERVAL);
                System.out.print(waitTime + "\n");
                // Wait for the result.   单位是毫秒
                try {
                    Thread.sleep(waitTime);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                // Get the result of the asynchronous operation.
                logger.info("第"+retries+"次请求 时间:"+new Date());
                Results result1 = getAsyncOperationResult();
                if (Results.SUCCESS == result1) {
                    retry = false;
                } else if (Results.Retry == result1) {
                    retry = true;
                } else {
                    // Some other error occurred, so stop calling the API.
                    retry = false;
                }
            } while (retry && (retries++ < MAX_RETRIES));
        }


        long end = System.currentTimeMillis();
        System.out.println(Thread.currentThread().getName() + "完成任务一,耗时:" + (end - start) + "毫秒");
        logger.info(Thread.currentThread().getName() + "完成任务一,耗时:" + (end - start) + "毫秒");

    }

    private Results getAsyncOperationResult() {

        System.out.println("do somethings");

        return Results.Retry;
    }

    /*
     * Returns the next wait interval, in milliseconds, using an exponential
     * backoff algorithm.
     */
    public static long getWaitTimeExp(int retryCount) {
        long waitTime = ((long) Math.pow(2, retryCount) * 1000L * 30);
        return waitTime;
    }

    public enum Results {
        SUCCESS,
        Retry
    }


}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值