分布式锁 DistributedLock.Core

DistributedLock 是一个 .NET 库,它基于各种底层技术,提供了健壮并且易于使用的分布式互斥锁、读写锁和信号量。
DistributedLock包含基于各种技术的实现,包括 SqlServer, Redis, Postgres, MySql 等,您可以根据自己的场景不同的实现库。

• DistributedLock.SqlServer
• DistributedLock.Postgres
• DistributedLock.MySql
• DistributedLock.Oracle
• DistributedLock.Redis
• DistributedLock.Azure
• DistributedLock.ZooKeeper
• DistributedLock.FileSystem
• DistributedLock.WaitHandles

在分布式场景中,使用 DistributedLock,跨多个应用程序/机器,控制对某个代码块的访问非常简单,如下

await using (await myDistributedLock.AcquireAsync())
{
    // 获取锁, 执行代码
}

DistributedLock.SqlServer 示例

var @lock = new SqlDistributedLock("MyLockName", connectionString);
await using (await @lock.AcquireAsync())
{
   // 获取锁, 执行代码
}

DistributedLock.Redis 示例

var connection = await ConnectionMultiplexer.ConnectAsync(connectionString); 
//  StackExchange.Redis

var @lock = new RedisDistributedLock("MyLockName", connection.GetDatabase());
await using (var handle = await @lock.TryAcquireAsync())
{
    if (handle != null) 
    { 
        // 获取锁, 执行代码
    }
}

Reader-writer locks 读写锁
DistributedLock 的读写锁实现和 .NET 中的 ReaderWriterLockSlim 类相似。
读写锁允许多个读取者或一个写入者在任何给定时间持有该锁。对于在可以安全进行并发访问,但有的时候又需要锁定的资源,是非常有用的,读写锁可用于在分布式缓存中提供线程安全性。

class DistributedCache
{
    // 使用 Sql Server 实现
    private readonly SqlDistributedReaderWriterLock _cacheLock = 
        new SqlDistributedReaderWriterLock("DistributedCache", connectionString);
        
    // 如果缓存中存在 key, 则返回,否则,生成新的 key,写入后并返回
    public async Task<object> GetOrCreateAsync(string key, Func<string, object> valueFactory)
    {
        // 首先,用 Read 锁尝试获取缓存数据
        await using (await this._cacheLock.AcquireReadLockAsync())
        {
            var cached = await this.GetValueOrDefaultNoLockAsync(key);
            if (cached != null) { return cached; }  
        }
        
        // 缓存不存在,用 Write 锁, 写入数据并返回
        await using (await this._cacheLock.AcquireWriteLockAsync())
        {
            // double-check: 检查是否已经被其他的进程写入数据
            var cached = await this.GetValueOrDefaultNoLockAsync(key);
            if (cached != null) { return cached; }  
            
            // 写入数据并返回
            var generated = valueFactory(key);
            await this.SetValueAsync(key, generated);
            return generated;
        }
    }
    
    private async Task<object?> GetValueOrDefaultNoLockAsync(string key) { /* 读取数据 */ }
    
    private async Task SetValueAsync(string key, object value) { /* 写入数据 */ }
}

*
*

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
@Slf4j @Aspect @Component public class DistributedLockAspect { private final ExpressionParser parser = new SpelExpressionParser(); private final DefaultParameterNameDiscoverer discoverer = new DefaultParameterNameDiscoverer(); @Autowired private RedissonClient redissonClient; @Around("@annotation(distributedLock)") public Object lock(ProceedingJoinPoint joinPoint, DistributedLock distributedLock) throws Throwable { // 使用spel解析注解中定义的key String keyValue = parseKeyValue(joinPoint, distributedLock.value()); // 拼接出锁名称 String lockName = connectLockName(distributedLock.keyPrefix(), keyValue, distributedLock.separator()); // 获取锁 RLock lock = getLock(distributedLock.lockModel(), lockName); try { if (lock.tryLock(distributedLock.waitLockMSec(), distributedLock.lockExpireMSec(), TimeUnit.MILLISECONDS)) { log.info("获取锁:{}", lockName); return joinPoint.proceed(); } throw new LockException(distributedLock.message()); } finally { lock.unlock(); } } private RLock getLock(DistributedLock.LockModel lockModel, String lockName) { switch (lockModel) { case FAIR: //公平锁 return redissonClient.getFairLock(lockName); case READ: //读之前加读锁,读锁的作用就是等待该lockkey释放写锁以后再读 return redissonClient.getReadWriteLock(lockName).readLock(); case WRITE: //写之前加写锁,写锁加锁成功,读锁只能等待 return redissonClient.getReadWriteLock(lockName).writeLock(); case REENTRANT: default: //可重入锁 return redissonClient.getLock(lockName); } } private String connectLockName(String prefix, String key, String separator) { if (StringUtils.isNotBlank(prefix)) { return prefix + separator + key; } return key; } private String parseKeyValue(ProceedingJoinPoint joinPoints, String elExpr) { MethodSignature methodSignature = (MethodSignature) joinPoints.getSignature(); Method method = methodSignature.getMethod(); //获取方法的参数值 Object[] args = joinPoints.getArgs(); EvaluationContext context = new StandardEvaluationContext(); String[] params = discoverer.getParameterNames(method); if (params != null) { for (int i = 0; i < params.length; i++) { context.setVariable(params[i], args[i]); } } //根据spel表达式获取值 Expression expression = parser.parseExpression(elExpr); Object value = expression.getValue(context); if (value != null) { return value.toString(); } return "defaultLockKey"; } }解释一下这段代码
03-23
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值