redis实现分布式锁
使用redis实现一个简单的分布式锁,主要是使用redis的setnx和getset方法进行实现。
加锁:
1.使用setnx设置值:
key:为需要加锁的锁名 value 为 当前时间+锁的超时时间
成功:
返回true 和锁的超时时间
失败:
根据key获取超时时间
为空:说明该锁已经释放了,重新获取锁
不为空:
判断锁是否已经超时
超时:
使用getset进行获取锁
如果返回的值和上一步获取的锁的超时时间一样说明获取锁,(当不一样时可能会导致将上一个线程设置的锁的超时时间进行修改,应该影响不大。)
没有超时:
说明锁被别的线程持有。
解锁:
解锁只可解除自己加的锁:
先获取锁的超时时间
为空:说明该锁已经不存在了
不为空: 根据加锁得到的返回值 和解锁得到的时间进行比较,如果一样说明是自己加的锁。
代码:
com.huan.redis.redis_lock.Lock.LockResult ---> 获取锁之后的返回值 用于判断是否获取锁 和 放入锁中的内容
com.huan.redis.redis_lock.Lock ---> 锁的接口
com.huan.redis.redis_lock.RedisLock ---> 锁的具体实现
锁的接口
package com.huan.redis.redis_lock;
/**
* 锁的接口
*
* @描述
* @作者 huan
* @时间 2016年10月30日 - 下午2:31:10
*/
public interface Lock {
LockResult lock(String lockName);
/**
* 获取锁
*
* @param lockName
* 需要上那一把锁
* @param lockTime
* 需要使用所的时间
* @param waitTime
* 当waitTime这个时间之内还没有获取到锁就退出获取锁
*/
LockResult lock(String lockName, long lockTime, long waitTime);
/**
* 释放锁
*
* @param lockName
*/
void unLock(String lockName, LockResult result);
static class LockResult {
private boolean lock;
private long info;
public LockResult(boolean lock, long info) {
super();
this.lock = lock;
this.info = info;
}
public boolean isLock() {
return lock;
}
public void setLock(boolean lock) {
this.lock = lock;
}
public long getInfo() {
return info;
}
public void setInfo(long info) {
this.info = info;
}
}
}
锁的具体实现
package com.huan.redis.redis_lock;
import java.text.SimpleDateFormat;
import java.util.Date;
import redis.clients.jedis.Jedis;
/**
* 使用redis实现分布式锁
*
* @描述
* @作者 huan
* @时间 2016年10月30日 - 下午2:39:11
*/
public class RedisLock implements Lock {
private Jedis jedis;
public RedisLock(Jedis jedis) {
this.jedis = jedis;
}
@Override
public LockResult lock(String lockName, long lockTime, long waitTime) {
long now = System.currentTimeMillis();
LockResult lockResult = new LockResult(false, 0);
while (System.currentTimeMillis() - now <= waitTime) { // 重试 直到超时
long needLockTime = System.currentTimeMillis() + lockTime;
if (jedis.setnx("lock:" + lockName, String.valueOf(needLockTime)) == 1) { // 获取锁
System.out.println(Thread.currentThread().getName() + " : 获取锁1.." + new SimpleDateFormat("yyyyMMdd HH:mm:ss").format(new Date()));
lockResult = new LockResult(true, needLockTime);
return lockResult;
}
String oldTime = jedis.get("lock:" + lockName); // 如果没有获取锁,则获取锁的持有时间
if (null != oldTime) { // 锁还在
if (System.currentTimeMillis() - Long.parseLong(oldTime) > 0) { // 锁已经超时
needLockTime = System.currentTimeMillis() + lockTime; // 计算新的锁超时时间
String _oldLockTime = jedis.getSet("lock:" + lockName, String.valueOf(needLockTime)); // 设置锁的超时时间
if (null != oldTime && _oldLockTime != null && oldTime.equals(_oldLockTime)) { // 获取锁
System.out.println(Thread.currentThread().getName() + " : 获取锁2.." + new SimpleDateFormat("yyyyMMdd HH:mm:ss").format(new Date()));
lockResult = new LockResult(true, needLockTime);
return lockResult;
} else {
// System.out.println("另外的线程释放锁.");
}
}
// System.out.println(Thread.currentThread().getName() + " : 尝试获取锁..");
} else { // 另外的线程释放锁,需要重新获取锁
needLockTime = System.currentTimeMillis() + lockTime; // 计算新的锁超时时间
if (jedis.setnx("lock:" + lockName, String.valueOf(needLockTime)) == 1) {
System.out.println(Thread.currentThread().getName() + " : 获取锁3.." + new SimpleDateFormat("yyyyMMdd HH:mm:ss").format(new Date()));
lockResult = new LockResult(true, needLockTime);
return lockResult;
}
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
Thread.currentThread().interrupt();
}
}
return lockResult;
}
@Override
public void unLock(String lockName, LockResult lockResult) {
String oldTime = jedis.get("lock:" + lockName);
if (null != oldTime && lockResult.isLock() && lockResult.getInfo() == Long.parseLong(oldTime)) {
System.out.println(Thread.currentThread().getName() + " 释放锁.." + new SimpleDateFormat("yyyyMMdd HH:mm:ss").format(new Date()));
jedis.del("lock:" + lockName);
} else {
if (0 == lockResult.getInfo()) {
System.out.println(Thread.currentThread().getName() + " : 获取锁失败...");
} else {
System.out.println(Thread.currentThread().getName() + " 持有的锁由于已经被被的线程修改锁不用次线程进行释放.");
}
}
}
@Override
public LockResult lock(String lockName) {
return lock(lockName, Long.MAX_VALUE, Long.MAX_VALUE);
}
}
测试:
本文来自博客园,作者:huan1993,转载请注明原文链接:https://www.cnblogs.com/huan1993/p/15416230.html