分布式锁

https://gitee.com/kekingcn/spring-boot-klock-starter

2  锁概念

2.1 公平锁:公平锁是指多个线程按照申请锁的顺序来获取锁,线程直接进入队列中排队,队列中的第一个线程才能获得锁。公平锁的优点是等待锁的线程不会饿死。缺点是整体吞吐效率相对非公平锁要低,等待队列中除第一个线程以外的所有线程都会阻塞,CPU唤醒阻塞线程的开销比非公平锁大。

2.2 非公平锁 多个线程加锁时直接尝试获取锁,获取不到才会到等待队列的队尾等待。但如果此时锁刚好可用,那么这个线程可以无需阻塞直接获取到锁,所以非公平锁有可能出现后申请锁的线程先获取锁的场景。非公平锁的优点是可以减少唤起线程的开销,整体的吞吐效率高,因为线程有几率不阻塞直接获得锁,CPU不必唤醒所有线程。缺点是处于等待队列中的线程可能会饿死,或者等很久才会获得锁。

2.3 可重入锁又名递归锁,是指在同一个线程在外层方法获取锁的时候,在进入内层方法会自动获取锁。说的有点抽象,下面会有一个代码的示例。

2.4 读写锁(ReadWriteLock)管理一组锁,一个是只读的锁,一个是写锁。读锁可以在没有写锁的时候被多个线程同时持有,写锁是独占的。所有读写锁的实现必须确保写操作对读操作的内存影响。换句话说,一个获得了读锁的线程必须能看到前一个释放的写锁所更新的内容。读写锁比互斥锁允许对于共享数据更大程度的并发。每次只能有一个写线程,但是同时可以有多个线程并发地读数据。ReadWriteLock适用于读多写少的并发情况;

3 Klock支持的锁  可重入锁,公平锁,读锁,写锁

4 参数

name:lock的name,对应redis的key值。默认为:类名+方法名,建议这个值不要为空

lockType:锁的类型,目前支持(可重入锁,公平锁,读写锁)。默认为:公平锁

waitTime:获取锁最长等待时间。默认为:60s。这个值单位为second;

leaseTime:获得锁后,自动释放锁的时间。默认为:60s。同时也可通过spring.klock.leaseTime统一配置

lockTimeoutStrategy: 加锁超时的处理策略,可配置为不做处理、快速失败、阻塞等待的处理策略,默认策略为不做处理

customLockTimeoutStrategy: 自定义加锁超时的处理策略,需指定自定义处理的方法的方法名,并保持入参一致。

releaseTimeoutStrategy: 释放锁时,持有的锁已超时的处理策略,可配置为不做处理、快速失败的处理策略,默认策略为不做处理

customReleaseTimeoutStrategy: 自定义释放锁时,需指定自定义处理的方法的方法名,并保持入参一致。

策略包括:

NO_OPERATION,继续执行业务逻辑,不做任何处理,这种情况下可能会掉用失败

FAIL_FAST 快速失败,加锁或者释放锁超时,报错,报错逻辑自行处理

KEEP_ACQUIRE  一直阻塞,直到获得锁,在太多的尝试后,仍会报错

demo:   例子在demo工程下的LockController

@Override
@Klock(name = "lockTest1", keys = "#id",
        waitTime = 2, leaseTime = 200,
        lockTimeoutStrategy = LockTimeoutStrategy.FAIL_FAST)
public String lockMethod1(Integer id) {
    ThreadUtil.safeSleep(100 1000);
    return ErrorCode.SUCCESS.getMessage();
}
 
@Override
@Klock(name = "lockTest1", keys = {"#lockParam.id""#lockParam.name"},
        waitTime = 2, leaseTime = 2,
        lockTimeoutStrategy = LockTimeoutStrategy.FAIL_FAST,
        releaseTimeoutStrategy = ReleaseTimeoutStrategy.NO_OPERATION
)
public String lockMethod2(LockParam lockParam) {
    ThreadUtil.safeSleep(100 1000);
    return ErrorCode.SUCCESS.getMessage();
}

6 redisson Client 原生

@ApiOperation(value = "lock测试")
@GetMapping(value = "/test/lock-redisson")
public String lockRedisson(@RequestParam LockParam lockParam) {
    String lockKey = "lock:test:redisson";
 
    //非公平锁
    RLock lock = redissonClient.getLock(lockKey);
 
    // 读写锁 ,参考 https://www.jianshu.com/p/9cd5212c8841
    RReadWriteLock readWriteLock = redissonClient.getReadWriteLock(lockKey);
 
    //可重入公平锁
    RLock fairLock = redissonClient.getFairLock(lockKey);
 
    try {
        boolean res = lock.tryLock(10, TimeUnit.SECONDS);
        if (res) {
            // to do somthing
            ThreadUtil.safeSleep(2000);
        }
    catch (InterruptedException e) {
        e.printStackTrace();
    finally {
        lock.unlock();
    }
    return "success";
}
posted @ 2022-05-23 15:02  姚春辉  阅读(192)  评论(0编辑  收藏  举报