需要讲解的 都写在注释里面了
package com.fuchanghai.redis.lock;
import java.util.List;
import java.util.UUID;
import ch.qos.logback.core.net.server.Client;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.Transaction;
import redis.clients.jedis.exceptions.JedisException;
public class RedisThread implements Runnable {
// 尝试着拿锁
/*
* @key 在redis 中的key
* @timeout 超时时间, 怕占用太多资源
* @expire 失效时长。怕程序上锁的时候, 程序崩溃了,没法解锁
* */
Jedis client=null;
public String getLock(String key ,int timeout, int expire){
try{
client= RedisManager.getClient();
// 这个值设置的是有一点讲究的, 因为setnx是锁住了, 但是其他线程是能够根据key 解锁的,所以我放入了
// 一个uuid 当解锁的时候我们比对value 是否相等来判断是否是当前线程加的锁
String value =UUID.randomUUID().toString();
//如果等于一就说明 设置成功
if(client.setnx(key, value)==1){
client.expire(key+"Lock", expire);
//这边返回json 是最好的 谁能保证a 里面没有,号呢, 到时候再分割就会出问题
return value;
}
if(client.ttl(key)==-1){
//如果进来了 说明没有设置失效时间。不设置的话,在当前代码之前某个线程setnx 成功了,但是程序崩溃了,岂不是一直要锁着
client.expire(key, expire);
}
}catch(Exception e){
e.printStackTrace();
}finally {
if(client!=null){
client.close();
}
}
return null;
}
public boolean releaseLock(String key ,String value){
Jedis client = RedisManager.getClient();
try {
System.out.println(value);
while (true) {
// 当watch 某个key 时,有多个线程对这个key操作, 将回滚
client.watch(key);
// 如果值相等,就说明是当前线程去删除这把锁
if (value.equals(client.get(key))) {
Transaction transation = client.multi();
transation.del(key);
List<Object> exec = transation.exec();
if (exec == null) {
//返回null 说明有多个线程对这个key 进行操作
continue;
}
return true;
}
client.unwatch();
break;
}
} catch (JedisException e) {
e.printStackTrace();
} finally {
if (client != null) {
client.close();
}
}
return false;
}
public void run() {
int count=0;
// TODO Auto-generated method stub
//如果失败再尝试两次
while(count<3){
String value=getLock("fuchanghai" ,10000, 5000);
if(value!=null){
System.out.println("业务操作");
releaseLock("fuchanghai", value);
}else{
count++;
}
}
}
}