Skip to content

组件讲解-分布式锁原理的详细剖析-下

在上篇文章中我们接受了分布式锁的切面实现的全部过程,而在本文中,本人将接着介绍分布式锁的方法级别的实现过程

依旧从自动装配作为入口来分析

ServiceLockAutoConfiguration

java
public class ServiceLockAutoConfiguration {
    
    /**
     * 分布式锁的key解析处理器
     * */
    @Bean(LockInfoType.SERVICE_LOCK)
    public LockInfoHandle serviceLockInfoHandle(){
        return new ServiceLockInfoHandle();
    }
    
    /**
     * 锁管理
     * */
    @Bean
    public ManageLocker manageLocker(RedissonClient redissonClient){
        return new ManageLocker(redissonClient);
    }
    
    /**
     * 锁工厂
     * */
    @Bean
    public ServiceLockFactory serviceLockFactory(ManageLocker manageLocker){
        return new ServiceLockFactory(manageLocker);
    }
    
    /**
     * 分布式锁切面
     * */
    @Bean
    public ServiceLockAspect serviceLockAspect(LockInfoHandleFactory lockInfoHandleFactory,ServiceLockFactory serviceLockFactory){
        return new ServiceLockAspect(lockInfoHandleFactory,serviceLockFactory);
    }
    /**
     * 分布式锁工具
     * */
    @Bean
    public ServiceLockTool serviceLockUtil(LockInfoHandleFactory lockInfoHandleFactory,ServiceLockFactory serviceLockFactory){
        return new ServiceLockTool(lockInfoHandleFactory,serviceLockFactory);
    }
}

ServiceLockAutoConfiguration是自动装配类,加载了 分布式锁的key解析处理器、分布式锁工厂、分布式锁切面、分布式锁工具的对象,而这个分布式锁工具 就是方法级别操作的api

ServiceLockTool

java
@AllArgsConstructor
public class ServiceLockTool {
    
    private final LockInfoHandleFactory lockInfoHandleFactory;
    
    private final ServiceLockFactory serviceLockFactory;
    
    /**
     * 没有返回值的加锁执行
     * @param taskRun 要执行的任务
     * @param name 锁的业务名
     * @param keys 锁的标识
     *
     * */
    public void execute(TaskRun taskRun,String name,String [] keys) {
        execute(taskRun,name,keys,20);
    } 

    /**
     * 没有返回值的加锁执行
     * @param taskRun 要执行的任务
     * @param name 锁的业务名
     * @param keys 锁的标识
     * @param waitTime 等待时间
     * 
     * */
    public void execute(TaskRun taskRun,String name,String [] keys,long waitTime){
        execute(LockType.Reentrant,taskRun,name,keys,waitTime);
    }
    
    /**
     * 没有返回值的加锁执行
     * @param lockType 锁类型
     * @param taskRun 要执行的任务
     * @param name 锁的业务名
     * @param keys 锁的标识
     *
     * */
    public void execute(LockType lockType,TaskRun taskRun,String name,String [] keys) {
        execute(lockType,taskRun,name,keys,20);
    }
    
    /**
     * 没有返回值的加锁执行
     * @param lockType 锁类型
     * @param taskRun 要执行的任务
     * @param name 锁的业务名
     * @param keys 锁的标识
     * @param waitTime 等待时间
     *
     * */
    public void execute(LockType lockType,TaskRun taskRun,String name,String [] keys,long waitTime) {
        LockInfoHandle lockInfoHandle = lockInfoHandleFactory.getLockInfoHandle(LockInfoType.SERVICE_LOCK);
        String lockName = lockInfoHandle.simpleGetLockName(name,keys);
        ServiceLocker lock = serviceLockFactory.getLock(lockType);
        boolean result = lock.tryLock(lockName, TimeUnit.SECONDS, waitTime);
        if (result) {
            try {
                taskRun.run();
            }finally {
                lock.unlock(lockName);
            }
        }else {
            LockTimeOutStrategy.FAIL.handler(lockName);
        }
    }

    /**
     * 有返回值的加锁执行
     * @param taskCall 要执行的任务
     * @param name 锁的业务名
     * @param keys 锁的标识
     * @return 要执行的任务的返回值
     * */
    public <T> T submit(TaskCall<T> taskCall,String name,String [] keys){
        LockInfoHandle lockInfoHandle = lockInfoHandleFactory.getLockInfoHandle(LockInfoType.SERVICE_LOCK);
        String lockName = lockInfoHandle.simpleGetLockName(name,keys);
        ServiceLocker lock = serviceLockFactory.getLock(LockType.Reentrant);
        boolean result = lock.tryLock(lockName, TimeUnit.SECONDS, 30);
        if (result) {
            try {
                return taskCall.call();
            }finally {
                lock.unlock(lockName);
            }
        }else {
            LockTimeOutStrategy.FAIL.handler(lockName);
        }
        return null;
    }
    
    /**
     * 获得锁
     * @param lockType 锁类型
     * @param name 锁的业务名
     * @param keys 锁的标识
     *
     * */
    public RLock getLock(LockType lockType, String name, String [] keys) {
        LockInfoHandle lockInfoHandle = lockInfoHandleFactory.getLockInfoHandle(LockInfoType.SERVICE_LOCK);
        String lockName = lockInfoHandle.simpleGetLockName(name,keys);
        ServiceLocker lock = serviceLockFactory.getLock(lockType);
        return lock.getLock(lockName);
    }
    
    /**
     * 获得锁
     * @param lockType 锁类型
     * @param lockName 锁名
     *
     * */
    public RLock getLock(LockType lockType, String lockName) {
        ServiceLocker lock = serviceLockFactory.getLock(lockType);
        return lock.getLock(lockName);
    }
}

execute加锁方法

此方法的加锁逻辑和切面的大致相同

java
public void execute(LockType lockType,TaskRun taskRun,String name,String [] keys,long waitTime) {
    //获取锁的名字解析处理器
    LockInfoHandle lockInfoHandle = lockInfoHandleFactory.getLockInfoHandle(LockInfoType.SERVICE_LOCK);
    //拼接锁的名字 LOCK:${name}:${key}
    String lockName = lockInfoHandle.simpleGetLockName(name,keys);
    //获得具体的锁类型
    ServiceLocker lock = serviceLockFactory.getLock(lockType);
    //进行加锁
    boolean result = lock.tryLock(lockName, TimeUnit.SECONDS, waitTime);
    //如果加锁成功
    if (result) {
        try {
            //执行业务逻辑
            taskRun.run();
        }finally {
            //解锁
            lock.unlock(lockName);
        }
    }else {
        //默认处理,快速失败
        LockTimeOutStrategy.FAIL.handler(lockName);
    }
}

TaskRun是要进行加锁的逻辑

java
@FunctionalInterface
public interface TaskRun {
    
    /**
     * 执行任务
     * */
    void run();
}

getLock加锁方法

这种加锁的方式和jdk中的Lock加锁方式相同,根据锁的类型和锁的名字以及锁的键值来获得锁的实例,然后用这个锁的实例来进行加锁和解锁的操作

java
/**
 * 获得锁
 * @param lockType 锁类型
 * @param name 锁的业务名
 * @param keys 锁的标识
 *
 * */
public RLock getLock(LockType lockType, String name, String [] keys) {
    LockInfoHandle lockInfoHandle = lockInfoHandleFactory.getLockInfoHandle(LockInfoType.SERVICE_LOCK);
    String lockName = lockInfoHandle.simpleGetLockName(name,keys);
    ServiceLocker lock = serviceLockFactory.getLock(lockType);
    return lock.getLock(lockName);
}

/**
 * 获得锁
 * @param lockType 锁类型
 * @param lockName 锁名
 *
 * */
public RLock getLock(LockType lockType, String lockName) {
    ServiceLocker lock = serviceLockFactory.getLock(lockType);
    return lock.getLock(lockName);
}

示例1

这种锁是使用命令模式加锁,加锁逻辑包装成TaskRun接口,传入execute方法,类似于线程池的提交

java
public void testLock(String name,long id){

    serviceLockTool.execute(() -> updateData(name,id),LOCK_DATA, new String[]{String.valueOf(id)});
}

public void updateData(String name,long id){
    //模拟修改数据
}

示例2

java
public void testLock(String name,long id){

    RLock lock = serviceLockTool.getLock(LockType.Reentrant, LOCK_DATA, new String[]{String.valueOf(id)});
    lock.lock();
    try {
        updateData(name,id);
    }finally {
        lock.unlock();
    }
}

public void updateData(String name,long id){
    //模拟修改数据
}

更新: 2025-10-13 11:51:17
原文: https://www.yuque.com/u22210564/ykdrdh/han0536p708u6thw

Java 后端面试知识库