JAVAマルチメソッドシーケンシャルロック

7461 ワード

前言
開発プロジェクトでは,データベースを同時に操作する複数の方法がデータの汚れ読みや幻読みの問題を生じていることを発見し,パケットを開発し,元のコードロジックに侵入せずに方法を順次実行させる.
使用方法の説明
ここで私が採用したのはうどんの元の論理を通じて前後の処理をします.元の論理に侵入しない【使用手順】一、挿抜性、コードパスの不一致を考慮して、起動クラスに注記@EnableMultiLockを付け、マルチメソッドロック2をオンにし、次に、ロックが必要なメソッドに注記@MultiMethodLockを付ける必要があります.以下に示すように、3つのメソッドに同名のロックを付け、test 1が実行されるとtest 2とtest 3が待機します、ロック待ち時間が予め設定されたタイムアウト時間を超えると、直接メソッドが実行されます.もちろん、それを死なせる必要がある場合は、タイムアウト時間を構成しなくてもいいので、最初のメソッドが完了してから実行されます.
@MultiMethodLock(timeout=1L,lockName="test")
public void test1(){
}
@MultiMethodLock(timeout=1L,lockName="test")
public void test2(){
}
@MultiMethodLock(timeout=1L,lockName="test")
public void test3(){
}

ソースコード説明
package com.wcf.lock.anotation.aspect;

import com.wcf.lock.anotation.MultiMethodLock;
import com.wcf.lock.utils.LockContainer;
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.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

/**
 * @author wangcanfeng
 * @description       
 * @date Created in 17:12-2020/1/15
 * @since 1.0.0
 */
@Aspect
@Component
public class MultiMethodLockAspect {

    private static final Logger log = LoggerFactory.getLogger(MultiMethodLockAspect.class);

    @Pointcut("@annotation(com.wcf.lock.anotation.MultiMethodLock)")
    public void lockAspect() {

    }

    @Around("lockAspect()")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
        Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
        MultiMethodLock ano = method.getAnnotation(MultiMethodLock.class);
        boolean isLock = false;
        if (ano != null) {
            isLock = LockContainer.tryLock(ano.lockName(), ano.timeout());
            if (!isLock) {
                log.warn("try to lock failed, then do job directly");
            }
        }
        //         
        Object result = null;
        try {
            result = joinPoint.proceed();
        } finally {
            if (isLock) {
                LockContainer.releaseLock(ano.lockName());
            }
        }
        return result;
    }
}

package com.wcf.lock.anotation;

import com.wcf.lock.conf.MultiLockConfig;
import org.springframework.context.annotation.Import;

import java.lang.annotation.*;

/**
 * @author wangcanfeng
 * @description          
 * @date Created in 19:02-2020/1/15
 * @since 1.0.0
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(MultiLockConfig.class)
public @interface EnableMultiLock {
}
package com.wcf.lock.anotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @author wangcanfeng
 * @description                  
 * @date Created in 10:38-2020/1/14
 * @since 1.0.0
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MultiMethodLock {
    /**
     *      ,       
     */
    long timeout() default 0;

    /**
     *    ,      ,       ,     
     */
    String lockName();

}
package com.wcf.lock.conf;

import com.wcf.lock.utils.LockContainer;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

import javax.annotation.PostConstruct;

/**
 * @author wangcanfeng
 * @description       
 * @date Created in 17:24-2020/1/15
 * @since 1.0.0
 */
@Configuration
@ComponentScan(basePackages = {"com.wcf.lock"})
public class MultiLockConfig {

    @PostConstruct
    public void init() {
        //       
        LockContainer.build();
    }
}
package com.wcf.lock.consts;

/**
 * @author wangcanfeng
 * @description      
 * @date Created in 10:57-2020/1/14
 * @since 1.0.0
 */
public class LockConsts {

    /**
     *        
     */
    public final static int DEFAULT_LOCK_TIME_OUT = 3000;
    /**
     *           
     */
    public final static int DEFAULT_LOCK_NUM_MAX = 200;
}

package com.wcf.lock.utils;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author wangcanfeng
 * @description    
 * @date Created in 11:03-2020/1/14
 * @since 1.0.0
 */
public class LockContainer {
    /**
     *      
     */
    private final static int DEFAULT_CAPACITY = 8;
    /**
     *     ,     ,     
     */
    private static Map locks;
    private final static Integer LOCK_HEADER = 0;
    public static void build() {
        locks = new ConcurrentHashMap<>(DEFAULT_CAPACITY);
    }

    /**
     *     :    ,      ,         
     *
     * @param lockName    
     * @author wangcanfeng
     * @date 2020/1/14-11:20
     * @since 1.0.0
     */
    public static void lock(String lockName) {
        tryLock(lockName, 0);
    }

    /**
     *     :    ,        
     *
     * @param lockName    
     * @param timeout            ,   
     * @return     :               
     * @author wangcanfeng
     * @date 2020/1/14-11:20
     * @since 1.0.0
     */
    public static boolean tryLock(String lockName, long timeout) {
        ReentrantLock lock;
        //             
        synchronized (LOCK_HEADER) {
            lock = locks.get(lockName);
            if (lock == null) {
                //       ,       ,          ,     
                lock = new ReentrantLock();
                locks.put(lockName, lock);
            }
        }
        //             
        //                 
        if (0 == timeout) {
            lock.lock();
            return true;
        } else {
            try {
                return lock.tryLock(timeout, TimeUnit.SECONDS);
            } catch (Exception e) {
                return false;
            }
        }
    }

    /**
     *     :       ,      
     *
     * @param lockName     
     * @author wangcanfeng
     * @date 2020/1/15-17:02
     * @since 1.0.0
     */
    public static void releaseLock(String lockName) {
        //             
        ReentrantLock lock = locks.get(lockName);
        if (lock == null) {
            return;
        }
        //        ,     
        if (lock.isLocked()) {
            lock.unlock();
        }
    }

    /**
     *     :       
     *
     * @return     :        
     * @author wangcanfeng
     * @date 2020/1/15-20:00
     * @since 1.0.0
     */
    public static List queryLocks() {
        List lockNames = new ArrayList<>();
        locks.forEach((k, v) -> lockNames.add(k));
        return lockNames;
    }
}


このロック保持者はまだ実現していません.
package com.wcf.lock.utils;

/**
 * @author wangcanfeng
 * @description     ,           ,          
 * @date Created in 11:11-2020/1/14
 * @since 1.0.0
 */
public class LockKeeper {

    private LockKeeper(){
        //NO_OP
    }
}

に続く
あとはここに施錠遅延、施錠監視などの機能も付いています.このマルチメソッドロックはまだ実践中ですが、何かアイデアがあれば提出してもいいですよ.できるだけ早く更新します.