java 重试_Java重试机制修改

最近无意间看到了一段代码,实话实说看的我有点难受,刚开始的时候还略微有点懵,只是感觉代码很长。等我捋了一遍之后,发现是一段调用远程接口,失败进行重试功能的代码。代码如下:

c06480731b6f

image.png

方法用到了递归,在重试次数小于零跳出。

说一下存在的问题吧:

接口重试和业务本身不发生关系,所以具有很高的耦合性

方法采用递归实现,有栈溢出的风险

重试逻辑无法进行重用

可配置性比较低

看下怎么改一下:

-抽离出重试代码,预留接口,业务代码填入,抽离工具类如下:

public abstract class MyRetryTemplate {

//重试次数

private int retryTime;

//重试时间

private int sleepTime;

//是否倍数增长

private boolean multiple = false;

/**

* 执行业务方法逻辑,由实现类实现

*

* @return

*/

public abstract T remote() throws Exception;

public T execute() throws InterruptedException {

for (int i = 1; i < retryTime + 1; i++) {

try {

return remote();

} catch (Exception e) {

System.out.println(e.getMessage());

if (multiple){

Thread.sleep(sleepTime);

}

else{

Thread.sleep(sleepTime * (i));

}

}

}

return null;

}

public T submit(ExecutorService executorService) {

Future submit = executorService.submit((Callable) () -> execute());

try {

return (T) submit.get();

} catch (InterruptedException | ExecutionException e) {

e.printStackTrace();

}

return null;

}

public MyRetryTemplate setRetryTime(int retryTime) {

this.retryTime = retryTime;

return this;

}

public MyRetryTemplate setSleepTime(int sleepTime) {

this.sleepTime = sleepTime;

return this;

}

public MyRetryTemplate setMultiple(boolean multiple) {

this.multiple = multiple;

return this;

}

}

上面的类中,值定义了重试的次数,间隔的时间,和时间的增长参数,预留了remote()抽象方法,交由具体的实现类来实现。类中使用了泛型,支持返回不同的对象。并且支持同步和异步调用。

看下修改后的代码,如下:

c06480731b6f

image.png

是不是感觉一下清爽了很多,这里重试相关的参数,我直接写死在了代码中,可以通过配置文件和数据库配置引入。这个方法应该还能精简,最后两句感觉还是有点多余,由于不知道是干啥的, 就暂且留在这吧。

修改后的代码,虽然解决了一些上面的问题,但是并没有完全解决,代码的侵入性,上面已经说了既然这是重试的逻辑,就不应该出现在代码中。有没有解决的办法呢,有,切面。

下面看下通过切面该怎么实现。

首先定义一个注解:

@Documented

@Target(ElementType.METHOD)

@Retention(RetentionPolicy.RUNTIME)

public @interface Retry {

int count() default 0 ;

long sleep() default 0 ;

}

定义切面

@Aspect

@Component

public class RetryAspect {

ExecutorService executorService = Executors.newFixedThreadPool(3);

@Around(value = "@annotation(Retry)")

public Object execute(ProceedingJoinPoint point, Retry retry) throws InterruptedException {

System.out.println("----------------- Aspect ---------------------");

MyRetryTemplate myRetryTemplate = new MyRetryTemplate() {

@Override

public ParametersHolder remote() throws Throwable {

return (ParametersHolder) point.proceed();

}

}.setRetryTime(3).setSleepTime(10000).submit(executorService);

return submit;

}

}

最终实现:

c06480731b6f

image.png

在注解中,添加自定义的参数,便可以实现零侵入,也更容易实现方法的复用,如果有其他的业务需要实现重试,直接在业务方法上添加注解即可。

如果不想用这种方法,也可以借助第三方工具guava-retrying和 spring-retry 来实现此功能。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java中,乐观锁机制通常用于解决多线程并发操作同一数据时可能出现的数据冲突问题。乐观锁是指在进行并发操作时,假设数据不会被其他线程修改,因此不会进行加锁,而是在更新数据时使用版本号(或时间戳)进行标识,以确保数据更新顺序的正确性。 乐观锁机制的基本思路是在更新数据时,先读取数据的版本号,然后进行更新操作。如果更新过程中发现版本号已经被其他线程修改,则说明数据已经被其他线程更新,此时需要进行操作,即新读取数据的最新版本号,再进行更新操作。操作可以复执行一定次数,直到数据更新成功或达到最大次数为止。 在Java中,乐观锁机制通常使用CAS操作(Compare And Swap)进行实现,CAS操作是一种无锁算法,它通过比较内存中的值和预期值是否相等来判断是否需要更新内存中的值,从而避免了使用锁的开销和风险。 下面是一个使用乐观锁机制的示例代码: ```java public class OptimisticLockDemo { private int value; private int version; public synchronized void update(int newValue) { int retryCount = 0; while (retryCount < MAX_RETRY_COUNT) { int currentVersion = version; if (compareAndSet(currentVersion, newValue, currentVersion + 1)) { return; } retryCount++; } throw new RuntimeException("Update failed after " + MAX_RETRY_COUNT + " retries."); } private boolean compareAndSet(int expectedVersion, int newValue, int newVersion) { synchronized (this) { if (version == expectedVersion) { value = newValue; version = newVersion; return true; } return false; } } } ``` 在这个示例代码中,我们使用了一个value变量来存储数据,一个version变量来存储版本号。在update方法中,我们使用了一个while循环来进行操作,如果次数超过了最大次数,则抛出异常。在compareAndSet方法中,我们使用了synchronized关键字来保证原子性,通过比较version值和expectedVersion值是否相等来判断是否需要进行更新操作。如果需要更新操作,则使用CAS操作来更新value和version的值。 需要注意的是,乐观锁机制并不是万能的,它只适用于并发更新操作比较少、冲突概率较低的情况。如果并发更新操作比较频繁、冲突概率较高,则可能会导致次数过多,影响性能。此时,建议使用悲观锁机制来保证数据的一致性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值