文章目录

  • 分布式锁场景和介绍:
  • 分布式锁模板类:
  • 锁实现类
  • lua脚本加锁和解锁
  • 分布式速度限制
  • 测试分布式锁

分布式锁场景和介绍:

分布式锁演进-基本原理


分布式锁演进-阶段一

分布式锁演进-阶段二

分布式锁演进-阶段三

分布式锁演进-阶段四

分布式锁演进-阶段五

分布式锁一般有如下的特点:

互斥性: 同一时刻只能有一个线程持有锁
可重入性: 同一节点上的同一个线程如果获取了锁之后能够再次获取锁
锁超时:和J.U.C中的锁一样支持锁超时,防止死锁
高性能和高可用: 加锁和解锁需要高效,同时也需要保证高可用,防止分布式锁失效
具备阻塞和非阻塞性:能够及时从阻塞状态中被唤醒

分布式锁模板类:

/*** 分布式锁模板类* Created by sunyujia@aliyun.com on 2016/2/23.*/
public interface DistributedLockTemplate {/**** @param lockId 锁id(对应业务唯一ID)* @param timeout 单位毫秒* @param callback 回调函数* @return*/public Object execute(String lockId,int timeout,Callback callback);
}
public interface DistributedReentrantLock {public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException;public void unlock();
}

回调接口:

/*** Created by sunyujia@aliyun.com on 2016/2/23.*/
public interface Callback {public Object onGetLock() throws InterruptedException;public Object onTimeout() throws InterruptedException;
}

锁实现类


/*** Created by sunyujia@aliyun.com on 2016/2/26.*/
public class RedisDistributedLockTemplate implements DistributedLockTemplate {private static final org.slf4j.Logger log = LoggerFactory.getLogger(RedisDistributedLockTemplate.class);private JedisPool jedisPool;public RedisDistributedLockTemplate(JedisPool jedisPool) {this.jedisPool = jedisPool;}@Overridepublic Object execute(String lockId, int timeout, Callback callback) {RedisReentrantLock distributedReentrantLock = null;boolean getLock=false;try {distributedReentrantLock = new RedisReentrantLock(jedisPool,lockId);if(distributedReentrantLock.tryLock(new Long(timeout), TimeUnit.MILLISECONDS)){getLock=true;return callback.onGetLock();}else{return callback.onTimeout();}}catch(InterruptedException ex){log.error(ex.getMessage(), ex);Thread.currentThread().interrupt();}catch (Exception e) {log.error(e.getMessage(), e);}finally {if(getLock) {distributedReentrantLock.unlock();}}return null;}
}

/*** Created by sunyujia@aliyun.com on 2016/2/26.*/
public class HHRedisDistributedLockTemplate implements DistributedLockTemplate {private static final org.slf4j.Logger log = LoggerFactory.getLogger(HHRedisDistributedLockTemplate.class);private JedisPool jedisPool;private Jedis jedis ;public HHRedisDistributedLockTemplate(JedisPool jedisPool) {this.jedisPool = jedisPool;this.jedis = jedisPool.getResource();}public boolean tryLock(String key, String ran, int timout){System.out.println("tryLock key:"+key+"ran:"+ran);Long val = jedis.setnx(key, ran);System.out.println("tryLock key:"+key+"ran:"+ran+"val:"+val);jedis.pexpire(key,timout);return  jedis.get(key).equals(ran);}public boolean unLock(String key, String value){if (value.equals(jedis.get(key))){jedis.del(key);System.out.println("unLock key:"+key+"val:"+value);}else{jedis.close();System.out.println("unlockERROR:"+"key:"+key+"expectVal:"+value+"val:"+jedis.get(key));return false;}jedis.close();return true;}@Overridepublic Object execute(String lockId, int timeout, Callback callback) {String ran = Thread.currentThread().getName();boolean getLock=false;try {if(tryLock(lockId,ran, timeout)){getLock=true;return callback.onGetLock();}else{return callback.onTimeout();}}catch(InterruptedException ex){log.error(ex.getMessage(), ex);Thread.currentThread().interrupt();}catch (Exception e) {log.error(e.getMessage(), e);}finally {if(getLock) {unLock(lockId,ran);}else{jedis.close();}}return null;}
}

lua脚本加锁和解锁

class RedisLockInternals {private static final org.slf4j.Logger log = LoggerFactory.getLogger(RedisLockInternals.class);private JedisPool jedisPool;/*** 重试等待时间*/private int retryAwait=300;private int lockTimeout=2000;RedisLockInternals(JedisPool jedisPool) {this.jedisPool = jedisPool;}String tryRedisLock(String lockId,long time, TimeUnit unit) {final long startMillis = System.currentTimeMillis();final Long millisToWait = (unit != null) ? unit.toMillis(time) : null;String lockValue=null;while (lockValue==null){lockValue=createRedisKey(lockId);if(lockValue!=null){break;}if(System.currentTimeMillis()-startMillis-retryAwait>millisToWait){break;}LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(retryAwait));}return lockValue;}private String createRedisKey(String lockId) {Jedis jedis = null;boolean broken = false;try {String value=lockId+randomId(1);jedis = jedisPool.getResource();即:
//            - 获取锁(unique_value可以是UUID等)
//            SET resource_name unique_value NX PX 30000
//
//                    - 释放锁(lua脚本中,一定要比较value,防止误解锁)
//            if redis.call("get",KEYS[1]) == ARGV[1] then
//            return redis.call("del",KEYS[1])
//else
//            return 0
//            endString luaScript = ""+ "\nlocal r = tonumber(redis.call('SETNX', KEYS[1],ARGV[1]));"+ "\nredis.call('PEXPIRE',KEYS[1],ARGV[2]);"+ "\nreturn r";List<String> keys = new ArrayList<String>();keys.add(lockId);List<String> args = new ArrayList<String>();args.add(value);args.add(lockTimeout+"");Long ret = (Long) jedis.eval(luaScript, keys, args);if( new Long(1).equals(ret)){return value;}}finally {if(jedis!=null) jedis.close();}return null;}void unlockRedisLock(String key,String value) {Jedis jedis = null;boolean broken = false;try {//String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return
//redis.call('del', KEYS[1]) else return 0 end";jedis = jedisPool.getResource();String luaScript=""+"\nlocal v = redis.call('GET', KEYS[1]);"+"\nlocal r= 0;"+"\nif v == ARGV[1] then"+"\nr =redis.call('DEL',KEYS[1]);"+"\nend"+"\nreturn r";List<String> keys = new ArrayList<String>();keys.add(key);List<String> args = new ArrayList<String>();args.add(value);Object r=jedis.eval(luaScript, keys, args);} finally {if(jedis!=null) jedis.close();}}private final static char[] digits = {'0', '1', '2', '3', '4', '5', '6', '7', '8','9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l','m', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y','z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L','M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y','Z'};private String randomId(int size) {char[] cs = new char[size];for (int i = 0; i < cs.length; i++) {cs[i] = digits[ThreadLocalRandom.current().nextInt(digits.length)];}return new String(cs);}public static void main(String[] args){System.out.println(System.currentTimeMillis());LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(300));System.out.println(System.currentTimeMillis());}
}

分布式速度限制

/*** 分布式速率限制 例如:限制n秒钟请求x次*/
public class AccessSpeedLimit {private static final org.slf4j.Logger log = LoggerFactory.getLogger(AccessSpeedLimit.class);private JedisPool jedisPool;public AccessSpeedLimit(){}public AccessSpeedLimit(JedisPool jedisPool) {this.jedisPool = jedisPool;}public JedisPool getJedisPool() {return jedisPool;}public void setJedisPool(JedisPool jedisPool) {this.jedisPool = jedisPool;}/*** 针对资源key,每seconds秒最多访问maxCount次,超过maxCount次返回false** @param key* @param seconds* @param limitCount* @return*/public boolean tryAccess(String key,int seconds,int limitCount){LimitRule limitRule=new LimitRule();limitRule.setLimitCount(limitCount);limitRule.setSeconds(seconds);return tryAccess(key,limitRule);}/*** 针对资源key,每limitRule.seconds秒最多访问limitRule.limitCount,超过limitCount次返回false* 超过lockCount 锁定lockTime* @param key* @param limitRule* @return*/public boolean tryAccess(String key,LimitRule limitRule){String newKey="Limit:"+key;Jedis jedis = null;boolean broken = false;long count=-1;try {jedis = jedisPool.getResource();List<String> keys = new ArrayList<String>();keys.add(newKey);List<String> args = new ArrayList<String>();args.add(Math.max(limitRule.getLimitCount(), limitRule.getLockCount())+"");args.add(limitRule.getSeconds()+"");args.add(limitRule.getLockCount()+"");args.add(limitRule.getLockTime()+"");count=Long.parseLong(jedis.eval(buildLuaScript(limitRule),keys,args)+"");return count<=limitRule.getLimitCount();} finally {if(jedis!=null)jedis.close();}}private String buildLuaScript(LimitRule limitRule){StringBuilder lua=new StringBuilder();lua.append("\nlocal c");lua.append("\nc = redis.call('get',KEYS[1])");lua.append("\nif c and tonumber(c) > tonumber(ARGV[1]) then");lua.append("\nreturn c;");lua.append("\nend");lua.append("\nc = redis.call('incr',KEYS[1])");lua.append("\nif tonumber(c) == 1 then");lua.append("\nredis.call('expire',KEYS[1],ARGV[2])");lua.append("\nend");if(limitRule.enableLimitLock()){lua.append("\nif tonumber(c) > tonumber(ARGV[3]) then");lua.append("\nredis.call('expire',KEYS[1],ARGV[4])");lua.append("\nend");}lua.append("\nreturn c;");return lua.toString();}
}

测试分布式锁

public class AccessSpeedLimitTest {@Testpublic void test1() throws InterruptedException {JedisPool jp=new JedisPool("localhost",6379);AccessSpeedLimit accessSpeedLimit=new AccessSpeedLimit(jp);SimpleDateFormat sdf=new SimpleDateFormat(" mm:ss");while(true){//10.0.0.1这个ip每1秒钟最多访问5次if块内代码.if(accessSpeedLimit.tryAccess("10.0.0.1", 1,5)){System.out.println("yes"+sdf.format(new Date()));}else{System.out.println("no"+sdf.format(new Date()));}Thread.sleep(100);}}@Testpublic void test2() throws InterruptedException {JedisPool jp=new JedisPool("127.0.0.1",6379);final RedisDistributedLockTemplate template=new RedisDistributedLockTemplate(jp);LimitRule limitRule=new LimitRule();limitRule.setSeconds(1);limitRule.setLimitCount(5);limitRule.setLockCount(7);limitRule.setLockTime(2);AccessSpeedLimit accessSpeedLimit=new AccessSpeedLimit(jp);SimpleDateFormat sdf=new SimpleDateFormat(" mm:ss");while(true){//10.0.0.1这个ip每1秒钟最多访问5次if块内代码.1秒超过10次后,锁定2秒,2秒内无法访问.if(accessSpeedLimit.tryAccess("10.0.0.1",limitRule)){System.out.println("yes"+sdf.format(new Date()));}else{System.out.println("no"+sdf.format(new Date()));}Thread.sleep(100);}}
}


【代码学习】lua+redis分布式锁代码实现实例相关推荐

  1. 这才叫细:带你深入理解Redis分布式锁

    什么是分布式锁 说到Redis,我们第一想到的功能就是可以缓存数据,除此之外,Redis因为单进程.性能高的特点,它还经常被用于做分布式锁. 锁我们都知道,在程序中的作用就是同步工具,保证共享资源在同 ...

  2. **Java有哪些悲观锁的实现_80% 人不知道的 Redis 分布式锁的正确实现方式(Java 版)...

    点击上方"小哈学Java",选择"星标" 回复"资源",领取全网最火的Java核心知识总结 来源:http://sina.lt/gfZU 前 ...

  3. Redis分布式锁的正确实现方式

    前言 分布式锁一般有三种实现方式:1. 数据库乐观锁:2. 基于Redis的分布式锁:3. 基于ZooKeeper的分布式锁.本篇博客将介绍第二种方式,基于Redis实现分布式锁.虽然网上已经有各种介 ...

  4. Redis分布式锁【正确实现方式】

    前言 分布式锁一般有三种实现方式:1. 数据库乐观锁:2. 基于Redis的分布式锁:3. 基于ZooKeeper的分布式锁.本篇博客将介绍第二种方式,基于Redis实现分布式锁.虽然网上已经有各种介 ...

  5. Redis分布式锁的正确实现方式(Java版)

    转自:https://wudashan.cn/2017/10/23/Redis-Distributed-Lock-Implement/ 前言 分布式锁一般有三种实现方式:1. 数据库乐观锁:2. 基于 ...

  6. Redis分布式锁---完美实现

    这几天在做项目缓存时候,因为是分布式的所以需要加锁,就用到了Redis锁,正好从网上发现两篇非常棒的文章,来和大家分享一下. 第一篇是简单完美的实现,第二篇是用到的Redisson. Redis分布式 ...

  7. Redis分布式锁问题

    https://blog.csdn.net/yb223731/article/details/90349502 https://www.jianshu.com/p/47fd7f86c848 一.什么是 ...

  8. Java版基于Redis分布式锁的实现方式

    一.什么是分布式锁? 要介绍分布式锁,首先要提到分布式锁相对应的线程锁和进程锁, 线程锁:组要是给方法.代码块加锁,当方法或者代码块使用锁时,在同一时刻只有一个线程可以执行该方法或者代码块,线程锁只在 ...

  9. Redis分布式锁的正确实现方式(转发来至博客园Ruthless )

    前言 分布式锁一般有三种实现方式:1. 数据库乐观锁:2. 基于Redis的分布式锁:3. 基于ZooKeeper的分布式锁.本篇博客将介绍第二种方式,基于Redis实现分布式锁.虽然网上已经有各种介 ...

最新文章

  1. java开源springboot项目_springBoot 搭建web项目(前后端分离,附项目源代码地址)...
  2. Siamese Network (应用篇2) :孪生网络用于图像块匹配 CVPR2015
  3. BZOJ 2038: [2009国家集训队]小Z的袜子(莫队算法例题)
  4. Java web 开发填坑记 2 -如何正确的创建一个Java Web 项目
  5. MySQL(MariaDB)之参数详解(-)
  6. Nginx server_name精确匹配配置
  7. Python基础语法:数据类型、进制转换、转义字符、字符编码、整数与浮点数运算规则、布尔型运算规则
  8. Vigenere加密法C++实现代码
  9. LeetCode 637. 二叉树的层平均值(层次遍历queue)
  10. 多段图的动态规划算法(C/C++)
  11. 移动端html头部meta标签的含义
  12. C# 代码注释生成代码提示和帮助文档
  13. Flume 知识点总结
  14. python人口普查数据数据分析_利用人口普查的收入数据来选一个好学校!
  15. 简单概率dp-hdu-4487-Maximum Random Walk
  16. Redis布隆过滤器和布谷鸟过滤器
  17. SRS 流媒体服务器对http-flv流进行配置
  18. [详细教程]jdk官方下载,Linux安装jdk1.7,图文解说,一看就会
  19. 《数学之美与浪潮之巅》读后感
  20. html链接打开excel表格,Excel表格中怎么设置超链接的形式打开其他Sheet工作簿

热门文章

  1. xpcom java_[Mozilla] JavaXPCOM 的jar 包概述
  2. shell-sort
  3. 什么插件格式化文档_推荐15款IntelliJ IDEA 神级插件
  4. HTML中From表单的常用type属性及用法【较全】
  5. java hibernate sqlserver自增_怎样在hibernate中实现oracle的主键自增策略?
  6. js中while死循环语句_Java系列教程day06——循环语句
  7. java中递归的概念_【Java】基础38:什么叫递归?
  8. 华为手表用鸿蒙了吗,华为鸿蒙都2.0了,手机还不能用吗?
  9. kaggle房价预测问题
  10. Bengio、周志华、山世光、包云岗等200+位AI学术领袖邀你观看智源大会精彩论坛...