基于redis实现分布式锁
相对于利用数据库实现分布式锁,利用redis来实现分布式锁,有以下几个优点
优点:
1.可以集群部署的,可以解决单点问题。
2.自带过期时间可以解决死锁问题。
可靠性介绍
- 互斥性。在任意时刻,只有一个客户端能持有锁。
- 不会发生死锁。即使有一个客户端在持有锁的期间崩溃而没有主动解锁,也能保证后续其他客户端能加锁。
- 具有容错性。只要大部分的Redis节点正常运行,客户端就可以加锁和解锁。
- 解铃还须系铃人。加锁和解锁必须是同一个客户端,客户端自己不能把别人加的锁给解了。
利用redis语句加锁。
set key value nx ex 2
解锁
delete key
问题所在:
虽然可以加入失效时间,一旦到了时间会自动删除锁,但是失效时间我设置多长时间为好?如何设置的失效时间太短,方法没等执行完,锁就自动释放了,那么就会产生并发问题。如果设置的时间太长,其他获取锁的线程就可能要平白的多等一段时间。这个问题使用数据库实现分布式锁同样存在。
package com.test; import redis.clients.jedis.Jedis; import java.util.concurrent.ConcurrentHashMap; /** * Created by edison on 2019/2/4. */ public class RedisJava { public static void main(String[] args) { //连接本地的 Redis 服务 Jedis jedis = new Jedis("192.168.43.150"); System.out.println("连接成功"); //查看服务是否运行 System.out.println("服务正在运行: "+jedis.ping()); ConcurrentHashMap cMap = new ConcurrentHashMap(); cMap.put("key1", "\"abc\""); cMap.put("key2", "\"def\""); cMap.put("key3", "\"ghk\""); System.out.println(cMap.toString()); StringBuffer sb = new StringBuffer(); sb.append("local lockKeys = " + cMap.toString() + " "); sb.append("local flag = 1 "); sb.append("for i,v in pairs(lockKeys) do "); sb.append(" local result = redis.call(\"set\",i, v,\"nx\",\"ex\", 20) "); sb.append("if type(result) ~= \"table\" then" ); sb.append(" flag = 0 "); sb.append(" break "); sb.append(" end "); sb.append(" end "); sb.append(" return flag "); System.out.println(sb.toString()); Long eval = (Long) jedis.eval(sb.toString()); System.out.println(eval); System.out.println("redis设置成功"); StringBuffer sb2 = new StringBuffer(); sb2.append("local lockKeys = " + cMap.toString() + " "); sb2.append("for i,v in pairs(lockKeys) do "); sb2.append(" redis.call(\"del\",i) "); sb2.append(" end "); Object eval1 = jedis.eval(sb2.toString()); System.out.println("redis请除成功"); } }