C#教程
主页 > 软件编程 > C#教程 >

Java实现自定义重试工具类介绍

2024-11-30 | 佚名 | 点击:

Spring-retry、guava的Retry都提供有重试工具,但二者均存在一个确缺点,即如果重试等待过程中会一直阻塞工作线程,这对于在生产环境使用是存在风险的,如果存在大量长时间等待的重试任务将会耗尽系统线程资源,下文基于线程池来完成一个简易的重试工具类。

核心思想

将任务封装为一个task,将任务的重试放入可调度的线程池中完成执行,避免在重试间隔中,线程陷入无意义的等待,同时将重试机制抽象为重试策略。

代码实现

重试工具类

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

package com.huakai.springenv.retry.v2;

 

import lombok.extern.slf4j.Slf4j;

 

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

import java.util.concurrent.ScheduledExecutorService;

import java.util.concurrent.TimeUnit;

import java.util.concurrent.atomic.AtomicInteger;

import java.util.function.Function;

 

@Slf4j

public class RetryUtil {

 

    public static ExecutorService EXECUTOR = Executors.newFixedThreadPool(1);

    private static final ScheduledExecutorService SCHEDULER_EXECUTOR = Executors.newScheduledThreadPool(20);

 

 

    /**

     * 任务重试

     * @param actualTaskFunction 执行的任务函数

     * @param resultHandler 任务结果处理器

     * @param maxRetry 最大重试次数

     * @param retryStrategy 重试策略

     */

    public static void retryTask(

            Function<Integer, String> actualTaskFunction,

            Function<String, Boolean> resultHandler,

            int maxRetry,

            RetryStrategy retryStrategy // 使用策略模式

    ) {

        Runnable runnable = new Runnable() {

            final AtomicInteger retryCount = new AtomicInteger(); // 当前重试次数

            final AtomicInteger maxRetryCount = new AtomicInteger(maxRetry); // 最大重试次数

 

            @Override

            public void run() {

                String taskResult = actualTaskFunction.apply(retryCount.get()); // 执行任务

                Boolean taskSuccess = resultHandler.apply(taskResult); // 处理任务结果

                if (taskSuccess) {

                    if (retryCount.get() > 1) {

                        log.info("任务重试成功,重试次数:{}", retryCount.get());

                    }

                    return; // 任务成功,不需要再重试

                }

 

                if (retryCount.incrementAndGet() == maxRetryCount.get()) {

                    log.warn("任务重试失败,重试次数:{}", retryCount.get());

                    return; // 达到最大重试次数,停止重试

                }

 

                // 获取重试间隔

                long delay = retryStrategy.getDelay(retryCount.get());

                TimeUnit timeUnit = retryStrategy.getTimeUnit(retryCount.get());

 

                // 安排下次重试

                SCHEDULER_EXECUTOR.schedule(this, delay, timeUnit);

                log.info("任务重试失败,等待 {} {} 后再次尝试,当前重试次数:{}", delay, timeUnit, retryCount.get());

            }

        };

        EXECUTOR.execute(runnable); // 执行任务

    }

 

    public static void main(String[] args) {

        // 使用指数退避重试策略

        RetryStrategy retryStrategy = new ExponentialBackoffRetryStrategy(1, TimeUnit.SECONDS);

 

        retryTask(

                retryCount -> "task result",

                taskResult -> Math.random() < 0.1,

                5,

                retryStrategy

        );

    }

}

重试策略

指数退避

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

package com.huakai.springenv.retry.v2;

 

import java.util.concurrent.TimeUnit;

 

/**

 * 指数退避重试策略

 */

public class ExponentialBackoffRetryStrategy implements RetryStrategy {

    private final long initialDelay;

    private final TimeUnit timeUnit;

 

    public ExponentialBackoffRetryStrategy(long initialDelay, TimeUnit timeUnit) {

        this.initialDelay = initialDelay;

        this.timeUnit = timeUnit;

    }

 

    @Override

    public long getDelay(int retryCount) {

        return (long) (initialDelay * Math.pow(2, retryCount - 1)); // 指数退避

    }

 

    @Override

    public TimeUnit getTimeUnit(int retryCount) {

        return timeUnit;

    }

}

自定义重试间隔时间

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

package com.huakai.springenv.retry.v2;

 

import java.util.List;

import java.util.concurrent.TimeUnit;

 

/**

 * 自定义重试间隔时间的重试策略

 */

public class CustomerIntervalRetryStrategy implements RetryStrategy {

    // 配置重试间隔和时间单位

    List<RetryInterval> retryIntervals;

 

 

    public CustomerIntervalRetryStrategy(List<RetryInterval> retryIntervals) {

        this.retryIntervals = retryIntervals;

    }

 

    @Override

    public long getDelay(int retryCount) {

        return retryIntervals.get(retryCount).getDelay();

    }

 

    @Override

    public TimeUnit getTimeUnit(int retryCount){

        return retryIntervals.get(retryCount).getTimeUnit();

    }

}

固定间隔

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

package com.huakai.springenv.retry.v2;

 

import java.util.concurrent.TimeUnit;

 

/**

 * 固定间隔重试策略

 */

public class FixedIntervalRetryStrategy implements RetryStrategy {

    private final long interval;

    private final TimeUnit timeUnit;

 

    public FixedIntervalRetryStrategy(long interval, TimeUnit timeUnit) {

        this.interval = interval;

        this.timeUnit = timeUnit;

    }

 

    @Override

    public long getDelay(int retryCount) {

        return interval;

    }

 

    @Override

    public TimeUnit getTimeUnit(int retryCount) {

        return timeUnit;

    }

}

原文链接:
相关文章
最新更新