SSDB分布式并发锁设计

在分布式环境中,由于synchronized关键字的局限性,需要设计分布式并发锁以保证资源访问有序。本文介绍了使用SSDB作为基础,利用其单线程原子性操作特性,通过incr操作实现分布式锁的详细设计。当线程请求资源时,通过incr操作判断是否已锁定,结合设置过期时间和循环尝试获取锁的策略,确保资源的正确访问。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

需求分析:

  1. 在分布式环境下,sychronized关键字并不能起到对资源加锁的作用,因为sychronized只能在同一个JVM中起作用,因此需要设计适合分布式应用部署的分布式并发锁,保证各个应用对同一资源的访问仍然有序进行
  2. SSDB能对分布式应用提供统一的基于内存的存储服务,而且性能很高,因此可被用来设计分布式锁,当然Redis也可以

详细设计:

  1. 基础:SSDB操作是单线程的,并且是原子的,因而不会有并发干扰问题,所有访问都是串行的
  2. 原理:
    1. 核心就是利用ssdb的incr操作,当第一个线程A来访问资源的时候,对key进行incr操作(此时key在ssdb中并没有值),结果为1,可以访问
    2. 再有线程B来访问资源时,如果第一个线程A还没有释放锁(del(key)),这时进行incr操作结果将大于1,表示资源已被锁住,不可访问
    3. 接下来线程B就每间隔一段时间循环执行incr操作,当第一个线程A释放锁(del(key))后,incr操作将返回1,此时获得锁,就可访问资源了
    4. 如下图所示
      这里写图片描述
  3. 需注意的地方
    1. 为防止意外原因导致线程锁住资源不放,每次incr(key)获得结果为1后,需要对key设置过期时间(ssdb.expire),一旦超过这个时间锁仍未释放,则ssdb自动删除key,这样接下来的线程将获得锁,过期时间应根据具体业务情况而定,我设置的是默认60s,可以在具体使用时再定义
    2. 当一个线程获取锁后,不可能立即释放,因此另一个线程来循环获取锁时,没必要不间断运行,可隔一个较短的时间再去尝试获取锁,我设置的是100ms

代码

@Component("ssdbLock")
public class SSDBLock{
       @Resource(name = "ssdbTemplate")
       private SSDBTemplate ssdbTemplate;

       private String lockKey = "ssdb:lock";
       private int ttl = 60;

       /**
        * 锁操作,默认key和过期时间
        * @throws Exception 
        */
       public void lock() throws Exception{
               lock(lockKey, ttl);
       }

       /**
        * 锁操作,指定key和过期时间
        * @param lockKey
        * @param ttl
        * @throws Exception 
        */
       public void lock(String lockKey, int ttl) throws Exception{
               boolean flag = getLock(lockKey, ttl);
               while(!flag){
                       Thread.sleep(WebConstants.DEFAULT_RETRY_LOCK_TERM);
                       flag = getLock(lockKey, ttl);
               }
       }

       /**
        * 获取锁
        * @param lockKey
        * @param ttl
        * @return
        * @throws Exception 
        */
       private boolean getLock(String lockKey, int ttl) throws Exception{
               boolean lock = false;
               Long result = ssdbTemplate.incr(lockKey);
               if(result == 1){
                       lock = true;
                       ssdbTemplate.expire(lockKey, ttl);
               }
               return lock;
       }

       /**
        * 释放锁,默认key
        */
       public void unlock(){
               try {
                       ssdbTemplate.delete(lockKey);
               } catch (Exception e) {
                       LoggerUtils.error(e);
               }
       }

       /**
        * 释放锁,指定key
        * @param lockKey
        */
       public void unlock(String lockKey){
               try {
                       ssdbTemplate.delete(lockKey);
               } catch (Exception e) {
                       LoggerUtils.error(e);
               }
       }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值