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; /** * Concurrent test retrial mechanism * * @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; // Number of concurrent threads executing simultaneously int
threadTotal = 20; int count = 0; ExecutorService executorService =
Executors.newCachedThreadPool(); // Semaphore , This is used to control the number of concurrent threads final Semaphore semaphore =
new Semaphore(threadTotal); // atresia , Counter decrement can be realized final CountDownLatch countDownLatch =
new CountDownLatch(clientTotal); for (int i = 0; i < clientTotal ; i++) {
executorService.execute(() -> { try { // Execute this method to obtain execution permission , When the total number of unreleased licenses does not exceed 200 Time ,
// Allow passage , Otherwise, the thread blocks and waits , Until you get permission . semaphore.acquire();
userAccountService.transfter(dto); // Release permit semaphore.release(); } catch
(Exception e) { //log.error("exception", e); e.printStackTrace(); } // Block minus one
countDownLatch.countDown(); }); }
countDownLatch.await();// Thread blocking , Until the locking value is 0 Time , It's blocked before it's released , Move on 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; /** * Update failed , Try retrying slicing * @author
rstyro */ @Aspect @Configuration public class TryAgainAspect { /** * How many retries by default */
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 { // Execute the business code again return pjp.proceed(); }
catch (TryAgainException ex) { if (numAttempts > maxRetries) { //log failure
information, and throw exception // If greater than Default retry mechanism frequency , We're really throwing it out this time throw new
ApiException(ApiResultEnum.ERROR_TRY_AGAIN_FAILED); }else{ // If
The maximum number of retries was not reached , Will be executed again System.out.println("===== Retrying ====="+numAttempts+" second "); } } }
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; /** * Update retry exception */ 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; /** * Custom api abnormal
* @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; /** * abnormal Return code */ public enum
ApiResultEnum { SUCCESS(200,"ok"), FAILED(400," request was aborted "), ERROR(500," Server error "),
ERROR_NULL(501," Null pointer exception "), ERROR_CLASS_CAST(502," Type conversion exception "),
ERROR_RUNTION(503," Runtime exception "), ERROR_IO(504," Abnormal upload file "),
ERROR_MOTHODNOTSUPPORT(505," Request method error "), ERROR_TRY_AGAIN(506," Retrying "),
ERROR_TRY_AGAIN_FAILED(507," Retrying failed "), // parameter PARAMETER_NULL(10001," Missing parameter or empty value "),
TRIGGER_GROUP_AND_NAME_SAME(10002," Group name and name already exist "), // account
ACCOUNT_LOCK(20001," Account locked "), ACCOUNT_NOT_FOUND(20002," Account information not found "),
ACCOUNT_PASSWARD_ERROR(20003," Wrong user name and password "), ACCOUNT_EXIST(20004," Account already exists "),
ACCOUNT_NOT_SUFFICIENT(20005," Insufficient account balance "), // jurisdiction AUTH_NOT_HAVE(30001," No authority "),
AUTH_SIGN_NOT_MATCH(30002," Signature mismatch "), FILE_IS_NULL(40001," The file is empty "),
FILE_NOT_PIC(40002," Not a picture type file "), TASK_IS_RUNING(50001," Task started , Unable to restart "),
TASK_IS_PAUSE(50002," The task is suspended , It can only be continued "), TASK_NOT_RUNING(50003," Task not executed , Cannot pause "),
EMS_CODE_NOT_FOUND(60000," Logistics number not found , Please fill in the logistics number "), ; 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; /** *
Global exception capture * @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(" Global exception ======== Retrying in progress ");
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); } }

Technology
©2019-2020 Toolsou All rights reserved,
golang One line of code converts the slice into a semicolon separated string keras Data generator -- Data enhancement C#/.NET System optimization (redis Chapter 6 data structure 【List】) Science fiction comes true !“ Trisomy ” Found out Huawei Mate 40 Pro+ 5G exposure : Leica film lens , Ceramic body Front end to background 5 Summary of different ways airflow Question series 2 —— task keep running Suspended animation mybatis Return result mapping of series Linux File name validity detection ( Essence )2020 year 6 month 26 day C# Class library File read and write operation help class