Redis实现分布式锁
2018-03-21 21:34:41
866次阅读
0个评论
使用java自带的lock框架可以很好的解决并发问题,但如果是分布式系统的话,就不能通过这个方法解决并发问题,此时可以使用redis实现并发锁来解决这个问题
使用redis锁有两个重要函数需要介绍
SETNX命令(SET if Not EXists)
语法:
SETNX key value
功能:
当且仅当 key 不存在,将 key 的值设为 value ,并返回1;若给定的 key 已经存在,则 SETNX 不做任何动作,并返回0。
GETSET命令
语法:
GETSET key value
功能:
将给定 key 的值设为 value ,并返回 key 的旧值 (old value),当 key 存在但不是字符串类型时,返回一个错误,当key不存在时,返回空。
使用redis锁有两个重要函数需要介绍
SETNX命令(SET if Not EXists)
语法:
SETNX key value
功能:
当且仅当 key 不存在,将 key 的值设为 value ,并返回1;若给定的 key 已经存在,则 SETNX 不做任何动作,并返回0。
GETSET命令
语法:
GETSET key value
功能:
将给定 key 的值设为 value ,并返回 key 的旧值 (old value),当 key 存在但不是字符串类型时,返回一个错误,当key不存在时,返回空。
使用java实现获取锁操作时,只需要使用setnx命令向redis中插值即可,(同时设置锁的最大持有时间,防止系统崩溃导致一直持有锁)代码片段如下:
/**
* 默认每个线程持有锁超时时间 30s
*/
private static final long LOCK_EXPIRE = 30;
/**
* redis锁前缀
*/
private static final String LOCK_PREFIX = "LOCK:";
/**
* 在指定时间内尝试获取redis锁,成功返回true,失败返回false,并设置锁的过期时间
*
* @Description
* @param key 锁标识
* @param timeout 等待获取锁的最大时间(秒)
* @param expire 锁过期失效时间(秒)
* @return
*/
public boolean lock(String key, long timeout, long expire)
{
long begin = 0;
do
{
if (tryLock(key, expire))
{
return true;
}
begin += 3;
try
{
Thread.sleep(3000);
}
catch (InterruptedException e)
{
logger.error("获取锁出错", e);
return false;
}
} while (begin <= timeout);
return false;
}
/**
* 尝试获取redis锁,成功返回true,失败返回false,并设置锁的过期时间
*
* @Description
* @param key 锁标识
* @param expire 锁过期失效时间(秒)
* @return
*/
public boolean tryLock(String key, long expire)
{
logger.info("try get lock for:" + key);
key = LOCK_PREFIX + key;
RedisConnection redisConnection = redisTemplate.getConnectionFactory().getConnection();
if (redisConnection.setNX(key.getBytes(), key.getBytes()))
{
redisTemplate.expire(key, expire, TimeUnit.SECONDS);
redisConnection.close();
return true;
}
redisConnection.close();
return false;
}
/**
* 在指定时间内尝试获取redis锁,成功返回true,失败返回false
*
* @Description
* @param key 锁标识
* @param timeout 等待获取锁的最大时间(秒)
* @return
*/
public boolean lock(String key, long timeout)
{
return lock(key, timeout, LOCK_EXPIRE);
}
/**
* 尝试获取redis锁,成功返回true,失败返回false
*
* @Description
* @param key 锁标识
* @return
*/
public boolean tryLock(String key)
{
return tryLock(key, LOCK_EXPIRE);
}
/**
* redis锁解锁
*
* @Description
* @author congyue.lu
* @param key 锁标识
*/
public void unLock(String key)
{
key = LOCK_PREFIX + key;
redisTemplate.delete(key);
}
redis加锁部分代码可以使用以下方式替换:
public boolean tryLock(String key, long expire)
{
logger.info("try get lock for:" + key);
key = LOCK_PREFIX + key;
final String keyStore = key;
boolean result = redisTemplate.execute(new RedisCallback<Boolean>()
{
@Override
public Boolean doInRedis(RedisConnection connection)
throws DataAccessException
{
Boolean result = connection.setNX(keyStore.getBytes(), keyStore.getBytes());
if (result)
{
connection.expire(keyStore.getBytes(), expire);
}
return result;
}
});
return result;
}
使用如上代码时,不必显示的关闭connection
00
相关话题