在电商项目中,经常有秒杀这样的活动促销,在并发访问下,很容易出现上述问题。如果在库存操作上,加锁就可以避免库存卖超的问题。分布式锁使分布式系统之间同步访问共享资源的一种方式

基于redis实现分布式锁的原理:

  redis为单进程单线程模式,采用队列模式将并发访问变成串行访问,且多客户端对Redis的连接并不存在竞争关系。其次Redis提供一些命令SETNX,GETSET,这些命令是原子操作,利用这些特性,

可以很充分的实现分布式锁。SETNX,GETSET 命令如下:

  SETNX key value

    功能:当且仅当 key 不存在,将 key 的值设为 value ,并返回1;若给定的 key 已经存在,则 SETNX 不做任何动作,并返回0。

  GETSET key value

    功能:将给定 key 的值设为 value ,并返回 key 的旧值 (old value),当 key 存在但不是字符串类型时,返回一个错误,当key不存在时,返回null

 实现要点:

  1、避免死锁,必要的超时机制。设置时间戳,时间戳要精确到毫秒。如果获取锁失败,则说明锁被其他对象保持,检查其是否超时

  2、释放锁时,避免释放非自己获得的锁,释放锁时,可以做一个是否超时的检查,如果超时说明锁就无需释放了

  3、为了造成不必要的资源浪费,提高并发,最好在最小颗粒度上的块加锁

  4、为了降低redis 压力,获取锁尝试时,循环之间一定要做sleep操作



参考源代码如下

// redis client

private Redistemplate tradeRedisTemplate



private Boolean setNX(String key, String value){

   return redisConnection.setNX(key.bytes, value.bytes)   

}



private String getSet(String key, String value){

   byte[] result = redisConnection.getSet(key.bytes, value.bytes)

   return new String(result)

}



//释放锁  key 锁名称,time 超时时间

public Void delDistributedLock(String key, Long time){

        String lastTimeS = tradeRedisTemplate.opsForValue().get(key)

        if(System.currentTimeMillis() - Long.parseLong(lastTimeS) < time){//避免删除非自己获取得到的锁

            tradeRedisTemplate.delete(key)

        }

}



//加锁 key 锁名称,time 超时时间

public Boolean acquireDistributedLock(String key, Long time){

        if(setNX(key, Long.toString(System.currentTimeMillis()))){ //SETNX成功,则成功获取一个锁

            return true

        }else{

            //SETNX失败,说明锁仍然被其他对象保持,检查其是否已经超时

            String lastTimeS = tradeRedisTemplate.opsForValue().get(key)

Long lastTime = Long.parseLong(lastTimeS)

//超时

            if(System.currentTimeMillis() - lastTime > time){

                String lastTimeRedis = getSet(key, Long.toString(System.currentTimeMillis()))

                if(lastTimeRedis.equals(lastTimeS)){// 获取锁成功

                    return true

                }

                // 已被其他进程捷足先登了

            }

        }

        return false

}

参考资料:

http://redis.io/commands/setnx

http://www.blogjava.NET/caojianhua/archive/2013/01/28/394847.html

最新文章

  1. JavaScript 对数据处理的5个API
  2. Eclipse更新SDK速度慢,解决办法
  3. [译]git log进阶
  4. 如何将自己的windows设置为mysql服务器
  5. SpringMVC学习系列(1) 之 初识SpringMVC
  6. ruby 程序中的文字编码
  7. 禁用和启用链接(a元素|LinkButton)的js方法
  8. 这个HEAD FIRST系统不错哟
  9. RPMForge——Quick Start build system
  10. Codeforces 506E Mr. Kitayuta&#39;s Gift (矩阵乘法,动态规划)
  11. git的基本应用(一)
  12. [20171211][转载]如何实现dbms_output输出没有打开serveroutput on.txt
  13. Javascript中构造函数的返回值问题和new对象的过程
  14. iOS控制器生命周期
  15. POJ 2488 DFS
  16. POJ2311 Cutting Game(博弈论)
  17. swoole学习
  18. Java复习第四天
  19. Objective-C中的instancetype和id关键字(转)
  20. avast从隔离区恢复后,仍无法打开被误杀文件的解决方案

热门文章

  1. SpringBootService,一个基于spring boot搭建的SOA服务框架
  2. XTemplate语法基础
  3. css3 transition属性
  4. iOS 开发者账号到期续费流程
  5. React Native之ListView使用
  6. [Modern OpenGL系列(四)]在OpenGL中使用Shader
  7. Maven详解
  8. web.xml 配置中classpath: 与classpath*:的区别
  9. SQL Server 2012 新特性:包含数据库访问数据库引擎
  10. Linux源码Kconfig文件语法分析