Java利用Redis(setnx、expire)实现分布式锁
【代码】Java利用Redis(setnx、expire)实现分布式锁。
·
原理:
原子性:利用setnx实现。SETNX 是『SET if Not eXists』(如果不存在,则 SET)的简写。时间复杂度O(1);
预防死锁:利用expire实现,超时通过redis的机制删除;
谁锁谁有权限解:传入一个value(随机生成),只要持有者才能释放掉锁(即del掉该key)
源码:
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
@Component
public class RedisService {
private Logger logger = LoggerFactory.getLogger(RedisService.class);
@Value("${spring.redis.database}")
private int dataBase;
@Autowired
private JedisPool jedisPool;
private final static String LOCK_KEY = "Distributed_";
/**
* 分布式锁,尝试获取锁
*
* @param scene 场景字段,不为空
* @param myId 线程标识,不为空
* @param maxLockSeconds 最大锁定时间,秒,大于0
* @return
*/
public Boolean tryLock(String scene, String myId, int maxLockSeconds) {
Jedis jedis = null;
try {
jedis = getJedis();
String key = LOCK_KEY + scene;
Long nxResult = jedis.setnx(key, myId);
if (nxResult.equals(1L)) {
jedis.expire(key, maxLockSeconds);
return true;
}
} catch (Exception e) {
logger.error("tryLock exception", e);
} finally {
returnResource(jedis);
}
logger.error("分布式锁,尝试获取锁-失败");
return false;
}
/**
* 分布式锁,释放锁
*
* @param scene 场景字段,不为空
* @param myId 线程标识,不为空
* @return
*/
public Boolean unLock(String scene, String myId) {
Jedis jedis = null;
try {
jedis = getJedis();
String key = LOCK_KEY + scene;
String value = jedis.get(key);
if (StringUtils.isNotEmpty(value) && value.equals(myId)) {
//哪个线程锁的,哪个线程解
return jedis.del(key).equals(1L);
}
} catch (Exception e) {
logger.error("unLock exception", e);
} finally {
returnResource(jedis);
}
logger.error("分布式锁,释放锁-失败");
return false;
}
private Jedis getJedis() {
Jedis jedis = jedisPool.getResource();
jedis.select(dataBase);
return jedis;
}
private void returnResource(Jedis jedis) {
if (jedis != null) {
jedis.close();
}
}
}
测试代码:
import junit.framework.TestCase;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import javax.annotation.Resource;
@SpringBootTest
@RunWith(SpringRunner.class)
public class RedisServiceTest extends TestCase {
private static final Logger logger = LoggerFactory.getLogger(RedisServiceTest.class);
@Resource
private RedisService redisService;
@Test
public void distributedLockTest() throws InterruptedException {
String myId = MD5Util.textToMD5L16(System.currentTimeMillis() + "");
String scene = "distributedLockTest";
Boolean lockResult = redisService.tryLock(scene, myId, 10);
if (lockResult) {
Thread.sleep(3000);//do some thing
Boolean unLockResult = redisService.unLock(scene, myId);
logger.error("释放锁:{}", unLockResult);
}
}
}
更多推荐
已为社区贡献3条内容
所有评论(0)