Redis实现分布式锁基于SetNx命令,因为在Redis中key是保证是唯一的。所以当多个线程同时的创建setNx时,只要谁能够创建成功谁就能够获取到锁。
SetNx命令每次SetNx检查该 key是否已经存在,如果已经存在的话不会执行任何操作。创建成功返回1,否则为0
1、需要的依赖jar包
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>
2、连接工具类
public class RedisUtil {
//protected static Logger logger = Logger.getLogger(RedisUtil.class);
private static StringIP ="192.168.0.104";
//Redis的端口号
private static int PORT =6379;
//可用连接实例的最大数目,默认值为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 JedisPooljedisPool =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,"123456");
}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);
}
}
}
3、redis实现分布式锁代码
public class RedisDistributedLock {
// setnx返回成功标识
private static final int LOCK_SUCCESS =1;
/**
* @param lockKey Redis中创建的键
* @param tryTimeout 尝试获取锁的超时时间
* @param timeout 键的超时时间
* @return
*/
public String getLock(String lockKey,int tryTimeout,int timeout) {
Jedis jedis = RedisUtil.getJedis();
// 获取锁的超时时间
Long endTime = System.currentTimeMillis() + tryTimeout;
// 当前时间在endTime之前,则可以尝试获取锁,否则退出
while (System.currentTimeMillis() < endTime) {
String lockValue = UUID.randomUUID().toString();
// 创建成功的获取锁
if (jedis.setnx(lockKey, lockValue) ==LOCK_SUCCESS) {
jedis.expire(lockKey, timeout /1000);
return lockValue;
}
}
if (jedis !=null) {
jedis.close();
}
return null;
}
public boolean unLock(String lockKey, String lockValue) {
Jedis jedis = RedisUtil.getJedis();
try {
// 保证谁获取锁谁释放
if (lockValue.equals(jedis.get(lockKey))) {
return jedis.del(lockKey) >0 ?true :false;
}
}catch (Exception e) {
e.printStackTrace();
}finally {
if (jedis !=null) {
jedis.close();
}
}
return false;
}
}