主要用到setnx函数,原理如下:
命令格式
SETNX key value
将 key 的值设为 value,当且仅当 key 不存在。
若给定的 key 已经存在,则 SETNX 不做任何动作。
SETNX 是SET if Not eXists的简写。
返回值
返回整数,具体为
- 1,当 key 的值被设置
- 0,当 key 的值没被设置
例子
redis> SETNX mykey “hello”
(integer) 1
redis> SETNX mykey “hello”
(integer) 0
redis> GET mykey
“hello”
redis>
使用SETNX实现分布式锁
多个进程执行以下Redis命令:
SETNX lock.foo <current Unix time + lock timeout + 1>
如果 SETNX 返回1,说明该进程获得锁,SETNX将键 lock.foo 的值设置为锁的超时时间(当前时间 + 锁的有效时间)。
如果 SETNX 返回0,说明其他进程已经获得了锁,进程不能进入临界区。进程可以在一个循环中不断地尝试 SETNX 操作,以获得锁。
package net.csdn.redis;
import java.util.concurrent.TimeUnit;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
public class RedisDemo {
private static JedisPool pool;
private static String redisServerIp = "192.168.0.43";
private static String redisPassord = "MMHlive2016";
private static int connectTimeout = 20 * 1000;// 2秒
/**
* 建立连接池 真实环境,一般把配置参数缺抽取出来。
*
*/
private static void createJedisPool() {
// 建立连接池配置参数
JedisPoolConfig config = new JedisPoolConfig();
// 设置最大连接数
config.setMaxActive(10000);
// 设置最大阻塞时间,记住是毫秒数milliseconds
config.setMaxWait(connectTimeout);
// 设置空间连接
config.setMaxIdle(500);
// 创建连接池
pool = new JedisPool(config, redisServerIp, 6379, connectTimeout, redisPassord);
}
/**
* 在多线程环境同步初始化
*/
private static synchronized void poolInit() {
if (pool == null)
createJedisPool();
}
/**
* 获取一个jedis 对象
*
* @return
*/
private static Jedis getJedis() {
if (pool == null)
poolInit();
return pool.getResource();
}
/**
* 归还一个连接
*
* @param jedis
*/
private static void returnRes(Jedis jedis) {
pool.returnResource(jedis);
}
public static long setnx(String key, String val, int timeout) {
Jedis jedis = getJedis();
long rst = jedis.setnx(key, val);
if (rst == 1) {
jedis.expire(key, timeout);
}
returnRes(jedis);
return rst;
}
public static long delete(String sessionId) {
Jedis jedis = getJedis();
Long rst = jedis.del(sessionId);
returnRes(jedis);
return rst;
}
public static boolean tryLock(String key, int timeout) {
long nano = System.nanoTime();
do {
Long i = setnx(key, key, timeout);
// System.out.println(i);
if (i == 1) {
System.out.println(Thread.currentThread().getName()+":获得锁");
return true;
}
if (timeout == 0) {
break;
}
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
if((System.nanoTime() - nano) > TimeUnit.SECONDS.toNanos(timeout)){
break;
}
} while (true);
throw new RuntimeException("获取[" + key + "]锁超时");
}
public static void main(String[] args) throws Exception {
String key="wweerrt";
delete(key);
int timeout=1000000;
new Thread(()->{
System.out.println(Thread.currentThread().getName()+":开始加锁");
tryLock(key, timeout);
}) .start();
new Thread(()->{
System.out.println(Thread.currentThread().getName()+":开始加锁");
tryLock(key, timeout);
}) .start();
Thread.sleep(100000L);
}
}
控制台输出:
Thread-1:开始加锁
Thread-2:开始加锁
Thread-1:获得锁