Redis實(shí)現(xiàn)分布式鎖基于SetNx命令,因?yàn)樵赗edis中key是保證是唯一的竣贪。所以當(dāng)多個(gè)線程同時(shí)的創(chuàng)建setNx時(shí)军洼,只要誰能夠創(chuàng)建成功誰就能夠獲取到鎖。
SetNx命令每次SetNx檢查該?key是否已經(jīng)存在贾富,如果已經(jīng)存在的話不會(huì)執(zhí)行任何操作歉眷。創(chuàng)建成功返回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的端口號(hào)
? ? private static int PORT =6379;
//可用連接實(shí)例的最大數(shù)目,默認(rèn)值為8畏纲;
//如果賦值為-1扇住,則表示不限制;如果pool已經(jīng)分配了maxActive個(gè)jedis實(shí)例盗胀,則此時(shí)pool的狀態(tài)為exhausted(耗盡)艘蹋。
? ? private static int MAX_ACTIVE =100;
//控制一個(gè)pool最多有多少個(gè)狀態(tài)為idle(空閑的)的jedis實(shí)例,默認(rèn)值也是8票灰。
? ? private static int MAX_IDLE =20;
//等待可用連接的最大時(shí)間女阀,單位毫秒,默認(rèn)值為-1屑迂,表示永不超時(shí)浸策。如果超過等待時(shí)間,則直接拋出JedisConnectionException惹盼;
? ? private static int MAX_WAIT =3000;
private static int TIMEOUT =3000;
//在borrow一個(gè)jedis實(shí)例時(shí)庸汗,是否提前進(jìn)行validate操作;如果為true手报,則得到的jedis實(shí)例均是可用的蚯舱;
? ? private static boolean TEST_ON_BORROW =true;
//在return給pool時(shí)改化,是否提前進(jìn)行validate操作;
? ? private static boolean TEST_ON_RETURN =true;
private static JedisPooljedisPool =null;
/**
* redis過期時(shí)間,以秒為單位
*/
? ? public final static int EXRP_HOUR =60 *60;//一小時(shí)
? ? public final static int EXRP_DAY =60 *60 *24;//一天
? ? public final static int EXRP_MONTH =60 *60 *24 *30;//一個(gè)月
/**
* 初始化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();
}
}
/**
* 在多線程環(huán)境同步初始化
*/
? ? private static synchronized void poolInit() {
if (jedisPool ==null) {
initialPool();
}
}
/**
* 同步獲取Jedis實(shí)例
*
? ? * @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實(shí)現(xiàn)分布式鎖代碼
public class RedisDistributedLock {
// setnx返回成功標(biāo)識(shí)
? ? private static final int LOCK_SUCCESS =1;
/**
? ? * @param lockKey? ? Redis中創(chuàng)建的鍵
? ? * @param tryTimeout 嘗試獲取鎖的超時(shí)時(shí)間
? ? * @param timeout? ? 鍵的超時(shí)時(shí)間
? ? * @return
? ? */
? ? public String getLock(String lockKey,int tryTimeout,int timeout) {
Jedis jedis = RedisUtil.getJedis();
// 獲取鎖的超時(shí)時(shí)間
? ? ? ? Long endTime = System.currentTimeMillis() + tryTimeout;
// 當(dāng)前時(shí)間在endTime之前陈肛,則可以嘗試獲取鎖,否則退出
? ? ? ? while (System.currentTimeMillis() < endTime) {
String lockValue = UUID.randomUUID().toString();
// 創(chuàng)建成功的獲取鎖
? ? ? ? ? ? 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;
}
}