消息队列确实是ok的,毕竟题主的需求来看无碍乎就是一个循环的重试,重试间隔需要指定,所以用延迟消息队列绝对能够解决问题,消息队列中间件选择很多

BaLaLaLs提到的rabbitmq确实需要一个插件来做,也可以选择RocketMQ,天生支持延迟消息,当然用redis去模拟一种延迟效果也是可以的

不过以上方案的选型,感觉需要额外多部署一些东西,假如系统之前并没有这方面的中间件,那可能为了做一个重试方案,显得有点大材小用了,毕竟确实真要实现,简单的循环,加上一些if判断就搞定了(至于占用线程资源倒是小事了),只是说这样的代码比较难看,而且也无法复用

我记得在Java轮子百宝屋Spring中,有一个工程:Spring Batch,这里面有一个重试的注解@Retryable,去看了一下,这一套API现在已经独立出来,名叫:Spring-Retry

简单的@Retryable注解配置就可以让一个方法直接具有重试效果(即使我不解释注解属性的含义,也应该能简单看懂重试规则)

java串口通信JSerial_java串口发送失败重试

执行该方法的效果

java串口通信JSerial_java串口发送失败重试_02

可以看到很简单就配置好了一套按照倍数增长间隔时间的重试方案

当然可以玩出很多效果,题主可以自己探索,但是为了解决题主的问题,我还是提前玩了一下,先说结论:

我自己反正试过已经有的API还不能支持题主30秒,3分钟,3小时的配置(或许我眼瞎没看到。。。)。毕竟他们之间的倍数没有特定的递增关系,可以看作是直接配置死了几次重试的间隔而已

由于注解@Retryable的实现重试的方式是按照已有的Spring-Retry配置的策略,所以我们得使用Spring-Retry提供的另一种方式去定制一个重试模版

先简单介绍一下,@Retryable的实现方式其实是基于一个拦截器的AnnotationAwareRetryOperationsInterceptor,而拦截器里面会去为被注解的方法创建一个RetryTemplate,这个RetryTemplate中包含了注解中的规则以及被注解的方法

所以定制重试模版的方式其实就是我们自己定义一个RetryTemplate,然后自己定义规则

先说规则,因为我们只是为了把一列间隔时间直接取出来然后重试,所以我们的规则就很简单,实现类CustomBackOffPolicy(以下截图并不是完整代码)

java串口通信JSerial_java串口发送失败重试_03

用一个Queue intervalQueue的方式简单粗暴的存储间隔时间,在需要取间隔时间直接调用poll方法,取队列首位并删除

然后我们就可以自定义RetryTemplate,间隔时间分别为1秒,5秒,10秒,其中SimpleRetryPolicy是Spring-Retry自带的,表示重试策略,参数就是重试次数,这里取的间隔数组长度+1(包括第一次失败,所以这里是4不是3)

java串口通信JSerial_模版_04

然后我们就可以去在需要重试的地方使用RetryTemplate了

java串口通信JSerial_模版_05

最后效果

java串口通信JSerial_消息队列_06

当然当然,说实话哈,Spring-Retry也算是造了一个轮子,但是其实哈仔细去查看一下Spring-Retry的实现模式,在题主的这个需求上,还是while循环然后用Sleep去停,哈哈哈哈,所以我最开始才说担心什么线程的资源占用,这都是小事,毕竟定时器或者什么定时任务这玩意儿,底层不都还是while循环嘛,所以我觉得我都可以给你整一个简要版,弄一个CustomRetryTemplate

java串口通信JSerial_java串口通信JSerial_07

然后调用的话也很简单

java串口通信JSerial_消息队列_08

最终效果也是一样的

java串口通信JSerial_模版_09

所有代码我都放在了github上,稍微有点多,就不在这里发了,可以自取哈

就酱,( ^_^ )/~~拜拜

最后再提一嘴,真要使用Spring-Retry,记得把spring-aspects的配置要加上哈,我的pom里是有的

java串口通信JSerial_消息队列_10