实际的项目开发过程中我们常常遇到高并发访问,容易导致数据不同步,例如:库存的增加, 故此我们可以通过Redis提供的特性实现分布式锁,以达到数据的同步性。本文主要通过客户端JedisLock来实现分布式锁。
注:该文是本博主记录学习之用,没有太多详细的讲解,敬请谅解!
1、实现思想:
(1)获取锁的时候,使用setnx加锁,锁的value值为一个超时时间,通过超时时间进行判断锁的占有与释放。
(2)释放锁的时候,判断是不是占有锁,若是占有锁,则执行delete进行锁释放。
com.github.jedis-lock
jedis-lock
1.0.0
package com.lance.net.server;
import com.github.jedis.lock.JedisLock;
import redis.clients.jedis.Jedis;
public class JedisLockTest {
public static void main(String[] args) throws InterruptedException {
for (int i=0;i<10;i++){
int num = i;
new Thread(new Runnable() {
@Override
public void run() {
Jedis jedis=new Jedis("127.0.0.1",6379);
lock(jedis,"key", num);
}
}).start();
}
}
public static void lock(Jedis jedis, String key,int i){
JedisLock jedisLock=new JedisLock(jedis,key,2000,2000);
try {
//获得锁
jedisLock.acquire();
System.out.println(i+"获得锁");
if(i==2){
//该代码块是为了验证效果
System.out.println(i+"睡眠2秒....");
Thread.sleep(2000);
}
}catch (Exception e){
e.printStackTrace();
}finally {
System.out.println(i+"释放锁");
if(jedisLock!=null){
//释放锁
jedisLock.release();
}
if(jedis!=null){
jedis.close();
}
}
}
}
对于JedisLock如何基于Redis来实现锁的效果,本文就不一一描述,各位可自行看源码理解!
以下贴上源码以供学习:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package com.github.jedis.lock;
import redis.clients.jedis.Jedis;
public class JedisLock {
Jedis jedis;
String lockKey;
int expireMsecs;
int timeoutMsecs;
boolean locked;
public JedisLock(Jedis jedis, String lockKey) {
this.expireMsecs = 60000;
this.timeoutMsecs = 10000;
this.locked = false;
this.jedis = jedis;
this.lockKey = lockKey;
}
public JedisLock(Jedis jedis, String lockKey, int timeoutMsecs) {
this(jedis, lockKey);
this.timeoutMsecs = timeoutMsecs;
}
public JedisLock(Jedis jedis, String lockKey, int timeoutMsecs, int expireMsecs) {
this(jedis, lockKey, timeoutMsecs);
this.expireMsecs = expireMsecs;
}
public JedisLock(String lockKey) {
this((Jedis)null, lockKey);
}
public JedisLock(String lockKey, int timeoutMsecs) {
this((Jedis)null, lockKey, timeoutMsecs);
}
public JedisLock(String lockKey, int timeoutMsecs, int expireMsecs) {
this((Jedis)null, lockKey, timeoutMsecs, expireMsecs);
}
public String getLockKey() {
return this.lockKey;
}
public synchronized boolean acquire() throws InterruptedException {
return this.acquire(this.jedis);
}
/**
* 获得 lock.
* 实现思路: 主要是使用了redis 的setnx命令,缓存了锁.
* reids缓存的key是锁的key,所有的共享, value是锁的到期时间(注意:这里把过期时间放在value了,没有时间上设置其超时时间)
* 执行过程:
* 1.通过setnx尝试设置某个key的值,成功(当前没有这个锁)则返回,成功获得锁
* 2.锁已经存在则获取锁的到期时间,和当前时间比较,超时的话,则设置新的值
*
*/
public synchronized boolean acquire(Jedis jedis) throws InterruptedException {
int timeout = this.timeoutMsecs;
while(timeout >= 0) {
long expires = System.currentTimeMillis() + (long)this.expireMsecs + 1L;
String expiresStr = String.valueOf(expires); //锁到期时间
if (jedis.setnx(this.lockKey, expiresStr) == 1L) {
this.locked = true;
return true;
}
//判断是否为空,不为空的情况下,如果被其他线程设置了值,则第二个条件判断是过不去的
//获取上一个锁到期时间,并设置现在的锁到期时间,
//只有一个线程才能获取上一个线上的设置时间,因为jedis.getSet是同步的
String currentValueStr = jedis.get(this.lockKey);
if (currentValueStr != null && Long.parseLong(currentValueStr) < System.currentTimeMillis()) {
String oldValueStr = jedis.getSet(this.lockKey, expiresStr);
if (oldValueStr != null && oldValueStr.equals(currentValueStr)) {
this.locked = true;
return true;
}
}
timeout -= 100;
Thread.sleep(100L);
}
return false;
}
public synchronized void release() {
this.release(this.jedis);
}
public synchronized void release(Jedis jedis) {
if (this.locked) {
jedis.del(new String[]{this.lockKey});
this.locked = false;
}
}
}
1、Redission实现分布式锁(官网推荐)
https://blog.csdn.net/weixin_43947588/article/details/90064064
2、Curator基于zookeeper实现分布式锁
https://blog.csdn.net/weixin_43947588/article/details/84893777
3、Jedis实现分布式锁
https://blog.csdn.net/weixin_43947588/article/details/98631392