分布式锁的实现方法

一、锁使用场景

    对公共区域数据并发访问,为防止数据脏读,脏写而使用锁。下面举例如下:从redis中取数据,做一定处理,再将处理后的数据压入,当多线程或多进程对同一个key对应的数据做处理时,就可能由于并发导最后的结果不是预期想要的。

二、锁的使用流程

      锁的大体使用流程都是获取锁,做数据处理,然后释放锁,流程图如下:

     

三、多线程同步锁

如果只是涉及单进程的多线程加锁,最简单的方法是在方法前加synchronized即可,当然这种方法有个缺点:如果同一个对象中所方法加了该锁,那某个线程调用该对象的一个方法,整个对象都会被锁住。

解决办法:1、封装不通对象。 2、在方法里去加锁

四、分布式锁

现在很多系统为了并发性、稳定性、扩展性,都是分布式部署,同一个服务会部署多套,而synchronized只能对单服务/进程起作用,多服务就锁不住了。这时需要使用到分布式锁,分布式锁其实原理也是一样的,多服务共用一套mysql、redis,这时通过mysql、redis去锁就能启动分布式锁的效果。下面以redis为例。

  1. 当只是对redis的key值做简单的自增某个值的操作,那这时只需要用redis的特定方法,redis天生就支持并发锁机制。

         直接调用redis的这个方法,这一个命令就包括读key对应的值,然后增加delta Long increment(K key, long delta);

     2、有些场景操作比较复杂,如根据key读出list列表,然后根据一定逻辑对list做处理,再将处理后的list压入,这时用redis自带的可能就不行了,得自己根据redis已有的方法封装分布式锁(当然,这种情况其实能避免就得尽量避免的,因为自己去封装的稳定速度都可能会差些)。

      加锁代码如下,当然这种方法还还是可能有问题,因为加锁和设置锁超时没有保持原子性,新版本redis可以直接将两个放到一条命令中,保持原子性

    public boolean lock(String value)
    {
        if (jedisTemplate.setnx(LOCK_KEY, value))
        {
            jedisTemplate.expire(LOCK_KEY,5,TimeUnit.SECONDS);
            return true;
        }
        
        return false;
    }

      解锁代码如下,增加value校验,是为了防止A进程的锁超时了,却还去释放锁,结果可能把B进程的锁给释放了。使用脚本,是为了保证原子性。

 

 public boolean unlock(String value)
    {         
        String script =
                "if redis.call('get',KEYS[1]) == ARGV[1] then" +
                        "   return redis.call('del',KEYS[1]) " +
                        "else" +
                        "   return 0 " +
                        "end";
        try 
        {
            Object result = jedis.eval(script, Collections.singletonList(LOCK_KEY), 
                                    Collections.singletonList(value));
            if("1".equals(result.toString()))
            {
                return true;
            }
            return false;
        }
        catch(Exception e)
        {
            return false;
        }
        finally 
        {
            jedis.close();
        } 
    }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值