Github地址:https://github.com/rstyro/optimistic-lock
optimistic-lock/src/main/java/top/lrshuai/optimisticlock/aspect/TryAgainAspect.javapackage top.lrshuai.optimisticlock.aspect;import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.ann...
文章共1,185字 · 阅读需要大约4分钟
一键AI生成摘要,助你高效阅读
问答
·
optimistic-lock/src/test/java/top/lrshuai/optimisticlock/ThreadTest.java
package top.lrshuai.optimisticlock;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import top.lrshuai.optimisticlock.usr.dto.TransferDTO;
import top.lrshuai.optimisticlock.usr.service.IUserAccountService;
import java.math.BigDecimal;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
@RunWith(SpringRunner.class)
@SpringBootTest
public class ThreadTest {
@Autowired
private IUserAccountService userAccountService;
/**
* 并发测试重试机制
*
* @throws Exception
*/
@Test
public void test() throws Exception {
TransferDTO dto = new TransferDTO();
dto.setFromUserId(1001l);
dto.setToUserId(1002l);
dto.setAmount(BigDecimal.ONE);
int clientTotal = 100;
// 同时并发执行的线程数
int threadTotal = 20;
int count = 0;
ExecutorService executorService = Executors.newCachedThreadPool();
//信号量,此处用于控制并发的线程数
final Semaphore semaphore = new Semaphore(threadTotal);
//闭锁,可实现计数器递减
final CountDownLatch countDownLatch = new CountDownLatch(clientTotal);
for (int i = 0; i < clientTotal ; i++) {
executorService.execute(() -> {
try {
//执行此方法用于获取执行许可,当总计未释放的许可数不超过200时,
//允许通行,否则线程阻塞等待,直到获取到许可。
semaphore.acquire();
userAccountService.transfter(dto);
//释放许可
semaphore.release();
} catch (Exception e) {
//log.error("exception", e);
e.printStackTrace();
}
//闭锁减一
countDownLatch.countDown();
});
}
countDownLatch.await();//线程阻塞,直到闭锁值为0时,阻塞才释放,继续往下执行
executorService.shutdown();
}
}
optimistic-lock/src/main/java/top/lrshuai/optimisticlock/aspect/TryAgainAspect.java
package top.lrshuai.optimisticlock.aspect;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.Transactional;
import top.lrshuai.optimisticlock.common.ApiException;
import top.lrshuai.optimisticlock.common.ApiResultEnum;
/**
* 更新失败,尝试重试切片
* @author rstyro
*/
@Aspect
@Configuration
public class TryAgainAspect {
/**
* 默认重试几次
*/
private static final int DEFAULT_MAX_RETRIES = 3;
private int maxRetries = DEFAULT_MAX_RETRIES;
private int order = 1;
public void setMaxRetries(int maxRetries) {
this.maxRetries = maxRetries;
}
public int getOrder() {
return this.order;
}
@Pointcut("@annotation(IsTryAgain)")
public void retryOnOptFailure() {
// pointcut mark
}
@Around("retryOnOptFailure()")
@Transactional(rollbackFor = Exception.class)
public Object doConcurrentOperation(ProceedingJoinPoint pjp) throws Throwable {
int numAttempts = 0;
do {
numAttempts++;
try {
//再次执行业务代码
return pjp.proceed();
} catch (TryAgainException ex) {
if (numAttempts > maxRetries) {
//log failure information, and throw exception
// 如果大于 默认的重试机制 次数,我们这回就真正的抛出去了
throw new ApiException(ApiResultEnum.ERROR_TRY_AGAIN_FAILED);
}else{
//如果 没达到最大的重试次数,将再次执行
System.out.println("=====正在重试====="+numAttempts+"次");
}
}
} while (numAttempts <= this.maxRetries);
return null;
}
}
optimistic-lock/src/main/java/top/lrshuai/optimisticlock/aspect/TryAgainException.java
package top.lrshuai.optimisticlock.aspect;
import top.lrshuai.optimisticlock.common.ApiException;
import top.lrshuai.optimisticlock.common.ApiResultEnum;
/**
* 更新重试异常
*/
public class TryAgainException extends ApiException {
public TryAgainException(ApiResultEnum apiResultEnum) {
super(apiResultEnum);
}
}
optimistic-lock/src/main/java/top/lrshuai/optimisticlock/common/ApiException.java
package top.lrshuai.optimisticlock.common;
import lombok.Data;
/**
* 自定义的api异常
* @author rstyro
*
*/
@Data
public class ApiException extends RuntimeException{
private static final long serialVersionUID = 1L;
private int status;
private String message;
private Object data;
private Exception exception;
public ApiException() {
super();
}
public ApiException(String message) {
super(message);
this.message=message;
}
public ApiException(int status, String message, Object data, Exception exception) {
super(message,exception);
this.status = status;
this.message = message;
this.data = data;
this.exception = exception;
}
public ApiException(ApiResultEnum apiResultEnum) {
this(apiResultEnum.getStatus(),apiResultEnum.getMessage(),null,null);
}
public ApiException(ApiResultEnum apiResultEnum, Object data) {
this(apiResultEnum.getStatus(),apiResultEnum.getMessage(),data,null);
}
public ApiException(ApiResultEnum apiResultEnum, Object data, Exception exception) {
this(apiResultEnum.getStatus(),apiResultEnum.getMessage(),data,exception);
}
}
optimistic-lock/src/main/java/top/lrshuai/optimisticlock/common/ApiResultEnum.java
package top.lrshuai.optimisticlock.common;
/**
* 异常 返回码
*/
public enum ApiResultEnum {
SUCCESS(200,"ok"),
FAILED(400,"请求失败"),
ERROR(500,"服务器错误"),
ERROR_NULL(501,"空指针异常"),
ERROR_CLASS_CAST(502,"类型转换异常"),
ERROR_RUNTION(503,"运行时异常"),
ERROR_IO(504,"上传文件异常"),
ERROR_MOTHODNOTSUPPORT(505,"请求方法错误"),
ERROR_TRY_AGAIN(506,"正在重试"),
ERROR_TRY_AGAIN_FAILED(507,"重试失败"),
//参数
PARAMETER_NULL(10001,"缺少参数或值为空"),
TRIGGER_GROUP_AND_NAME_SAME(10002,"组名和名称已存在"),
//账户
ACCOUNT_LOCK(20001,"账号已锁定"),
ACCOUNT_NOT_FOUND(20002,"找不到账户信息"),
ACCOUNT_PASSWARD_ERROR(20003,"用户名密码错误"),
ACCOUNT_EXIST(20004,"账号已存在"),
ACCOUNT_NOT_SUFFICIENT(20005,"账号余额不足"),
//权限
AUTH_NOT_HAVE(30001,"没有权限"),
AUTH_SIGN_NOT_MATCH(30002,"签名不匹配"),
FILE_IS_NULL(40001,"文件为空"),
FILE_NOT_PIC(40002,"不是图片类型文件"),
TASK_IS_RUNING(50001,"任务已启动,无法再起启动"),
TASK_IS_PAUSE(50002,"任务暂停,只可继续执行"),
TASK_NOT_RUNING(50003,"任务未执行,无法暂停"),
EMS_CODE_NOT_FOUND(60000,"物流编号找不到,请填写物流编号"),
;
private int status;
private String message;
public String getMessage() {
return message;
}
public int getStatus() {
return status;
}
private ApiResultEnum(int status,String message) {
this.status = status;
this.message = message;
}
}
optimistic-lock/src/main/java/top/lrshuai/optimisticlock/config/
package top.lrshuai.optimisticlock.config;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import top.lrshuai.optimisticlock.aspect.TryAgainException;
import top.lrshuai.optimisticlock.common.ApiException;
import top.lrshuai.optimisticlock.common.ApiResultEnum;
import top.lrshuai.optimisticlock.common.Result;
import java.io.IOException;
/**
* 全局异常捕获
* @author rstyro
* @since 2019-03-12
*/
@RestControllerAdvice
public class GlobalExceptionHandler {
private Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
@ExceptionHandler(NullPointerException.class)
public Result NullPointer(NullPointerException ex){
logger.error(ex.getMessage(),ex);
return Result.error(ApiResultEnum.ERROR_NULL);
}
@ExceptionHandler(ClassCastException.class)
public Result ClassCastException(ClassCastException ex){
logger.error(ex.getMessage(),ex);
return Result.error(ApiResultEnum.ERROR_CLASS_CAST);
}
@ExceptionHandler(IOException.class)
public Result IOException(IOException ex){
logger.error(ex.getMessage(),ex);
return Result.error(ApiResultEnum.ERROR_IO);
}
@ExceptionHandler(HttpRequestMethodNotSupportedException.class)
public Result HttpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException ex){
logger.error(ex.getMessage(),ex);
return Result.error(ApiResultEnum.ERROR_MOTHODNOTSUPPORT);
}
@ExceptionHandler(TryAgainException.class)
public Result TryAgainException(TryAgainException ex) {
logger.error("全局异常========正在重试");
return Result.error(ex.getStatus(),ex.getMessage());
}
@ExceptionHandler(ApiException.class)
public Result ApiException(ApiException ex) {
logger.error(ex.getMessage(),ex);
return Result.error(ex.getStatus(),ex.getMessage());
}
@ExceptionHandler(RuntimeException.class)
public Result RuntimeException(RuntimeException ex){
logger.error(ex.getMessage(),ex);
return Result.error(ApiResultEnum.ERROR_RUNTION);
}
@ExceptionHandler(Exception.class)
public Result exception(Exception ex){
logger.error(ex.getMessage(),ex);
return Result.error(ApiResultEnum.ERROR);
}
}
更多推荐
已为社区贡献1条内容
所有评论(0)