一、Redis分布式锁实现思路
Redis实现分布式锁基于SetNx命令,因为在Redis中key是保证是唯一的。所以当多个线程同时的创建setNx时,只要谁能够创建成功谁就能够获取到锁。
Set 命令 每次set时,可以修改原来旧值;
SetNx命令 每次SetNx检查该 key是否已经存在,如果已经存在的话不会执行任何操作。返回为0 如果已经不存在的话直接新增该key。
1:新增key成功 0 失败
获取锁的时候:当多个线程同时创建SetNx k,只要谁能够创建成功谁就能够获取到锁。
释放锁:可以对该key设置一个有效期可以避免死锁的现象。
二、Zookeeper实现分布式锁思路
Zookeeper实现分布式锁核心采用临时节点+事件通知,因为zk节点路径是保证全局唯一的,当多个线程同时创建该临时节点,只要谁能够创建成功谁就能够获取到锁。
获取锁:当多个线程同时创建该临时节点,只要谁能够创建成功谁就能够获取到锁。
释放锁:关闭当前Session连接,自动的删除当前的zk节点路径,其他线程重新进入到获取锁阶段。
三、分布式锁的应用场景有那些
1.分布式任务调度平台保证任务的幂等性。
2.分布式全局id的生成
四、Redis分布式锁核心代码
1. Maven
<dependencies>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.9</version>
</dependency>
</dependencies>
2. Service
package com.demo.service;
import com.demo.utils.DemoRedisLock;
import org.apache.commons.lang3.StringUtils;
/**
* @Author: JYC
* @Title: OrderService
* @Description: TODO
* @Date: 2022/4/29 14:37
*/
public class OrderService {
private static final String LOCKKEY = "demo_lock";
public static void service() {
// 1. 获取锁
DemoRedisLock demoRedisLock = new DemoRedisLock();
String lockValue = demoRedisLock.getLock(LOCKKEY, 5000, 5000);
if (StringUtils.isEmpty(lockValue)) {
System.out.println(Thread.currentThread().getName() + ",获取锁失败了");
return;
}
// 2.执行我们的业务逻辑
System.out.println(Thread.currentThread().getName() + ",获取锁成功:lockValue:" + lockValue);
// 3.释放锁
demoRedisLock.unLock(LOCKKEY, lockValue);
}
public static void main(String[] args) {
service();
}
}
3. utils
package com.demo.utils;
import redis.clients.jedis.Jedis;
import java.util.UUID;
/**
* @Author: JYC
* @Title: MayiktRedisLock
* @Description: TODO
* @Date: 2022/4/29 14:19
*/
public class DemoRedisLock {
private static int lockSuccess = 1;
/**
* @param lockKey 在redis中创建的key值
* @param notLockTime 尝试获取锁超时时间
* @return 返回lock成功值
*/
public String getLock(String lockKey, int notLockTime, int timeOut) {
// 获取Redis链接
Jedis jedis = RedisUtil.getJedis();
// 计算我们尝试获取锁的超时时间
Long endTime = System.currentTimeMillis() + notLockTime;
// 当前系统时间小于endTime说明获取锁没有超时,继续循环,否则情况下退出循环
while (System.currentTimeMillis() < endTime) {
String lockValue = UUID.randomUUID().toString();
// 当前多个不同的jvm同时创建一个相同的rediskey 只要谁能够创建成功谁就能够获取锁
if (jedis.setnx(lockKey, lockValue) == lockSuccess) {
// 加上有效日期
jedis.expire(lockKey, timeOut / 1000);
return lockValue;
// 退出循环
}
// 否则情况下 继续循环
}
try {
if (jedis != null) {
jedis.close();
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 释放锁
*
* @return
*/
public boolean unLock(String lockey, String lockValue) {
// 获取Redis链接
Jedis jedis = RedisUtil.getJedis();
try {
// 判断获取锁的时候保证自己删除自己
if (lockValue.equals(jedis.get(lockey))) {
return jedis.del(lockey) > 0 ? true : false;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (jedis != null) {
jedis.close();
}
}
return false;
}
}
package com.demo.utils;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
public class RedisUtil {
//protected static Logger logger = Logger.getLogger(RedisUtil.class);
private static String IP = "192.168.1.100";
//Redis的端口号
private static int PORT = 6379;
private static String PASSWORD = "root";
//可用连接实例的最大数目,默认值为8;
//如果赋值为-1,则表示不限制;如果pool已经分配了maxActive个jedis实例,则此时pool的状态为exhausted(耗尽)。
private static int MAX_ACTIVE = 100;
//控制一个pool最多有多少个状态为idle(空闲的)的jedis实例,默认值也是8。
private static int MAX_IDLE = 20;
//等待可用连接的最大时间,单位毫秒,默认值为-1,表示永不超时。如果超过等待时间,则直接抛出JedisConnectionException;
private static int MAX_WAIT = 3000;
private static int TIMEOUT = 3000;
//在borrow一个jedis实例时,是否提前进行validate操作;如果为true,则得到的jedis实例均是可用的;
private static boolean TEST_ON_BORROW = true;
//在return给pool时,是否提前进行validate操作;
private static boolean TEST_ON_RETURN = true;
private static JedisPool jedisPool = null;
/**
* redis过期时间,以秒为单位
*/
public final static int EXRP_HOUR = 60 * 60; //一小时
public final static int EXRP_DAY = 60 * 60 * 24; //一天
public final static int EXRP_MONTH = 60 * 60 * 24 * 30; //一个月
/**
* 初始化Redis连接池
*/
private static void initialPool() {
try {
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxTotal(MAX_ACTIVE);
config.setMaxIdle(MAX_IDLE);
config.setMaxWaitMillis(MAX_WAIT);
config.setTestOnBorrow(TEST_ON_BORROW);
jedisPool = new JedisPool(config, IP, PORT, TIMEOUT, PASSWORD);
} catch (Exception e) {
//logger.error("First create JedisPool error : "+e);
e.getMessage();
}
}
/**
* 在多线程环境同步初始化
*/
private static synchronized void poolInit() {
if (jedisPool == null) {
initialPool();
}
}
/**
* 同步获取Jedis实例
*
* @return Jedis
*/
public synchronized static Jedis getJedis() {
if (jedisPool == null) {
poolInit();
}
Jedis jedis = null;
try {
if (jedisPool != null) {
jedis = jedisPool.getResource();
}
} catch (Exception e) {
e.getMessage();
// logger.error("Get jedis error : "+e);
}
return jedis;
}
/**
* 释放jedis资源
*
* @param jedis
*/
public static void returnResource(final Jedis jedis) {
if (jedis != null && jedisPool != null) {
jedisPool.returnResource(jedis);
}
}
public static Long sadd(String key, String... members) {
Jedis jedis = null;
Long res = null;
try {
jedis = getJedis();
res = jedis.sadd(key, members);
} catch (Exception e) {
//logger.error("sadd error : "+e);
e.getMessage();
}
return res;
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/131233.html