Redis分布式锁之ReentrantLock

直接上代码

package persistent.prestige.redis.lock;

import persistent.prestige.redis.RedisUtils;
import redis.clients.jedis.Jedis;

/**
* 基于 redis 实现 公平的、自旋式、 分布式锁
* 实现思路:
* 使用队列保持请求锁的顺序,请求线程在上一个线程的锁定状态自旋等待。
* 获取锁实现:
* 首先使用redis rpush命令向redis队列增加一个元素,该命令返回队列的当前长度,如果为1,表示没有其他线程尝试获取锁,该方法立即返回
* 如果长度不为1,则表示,在该线程之前,已经有线程在等待锁或占有锁,需要在该队列倒数第二个上自选(inx = len - 2 jedis.lindex(listKey(), len - 2 ).equals("1")),并将该线程所在队列的位置放入ThreadLocal变量中
*
* 释放锁实现:
* 只需要将该线程所在队列位置中的值设置为0,即可
*
*
* 目前不足的地方,队列会随着需要获取锁的线程的增长,队列长度会增长,lindex命令的时间复杂度为o(n)。
*
* @author dingwei2
*
*/
public class ReentrantLock implements Lock {
/** 默认key前缀 */
public static final String DEFAULT_KEYPRIX = "persistent:prestige:redis:lock:ReentrantLock:";

private static final String LIST_KEY = "list";

//记录该线程在队列中的位置
private ThreadLocal<Integer> positionLocal = new ThreadLocal<Integer>();

private String keyprix;

public ReentrantLock() {
this.keyprix = DEFAULT_KEYPRIX;
}

/**
* 构造方法提供改变key前缀
* @param keyprix
*/
public ReentrantLock(String keyprix) {
this.keyprix = keyprix;
}

@Override
public void lock() {
// TODO Auto-generated method stub
System.out.println(Thread.currentThread().getName() + " 尝试获取锁");
Jedis jedis = null;
try {
jedis = RedisUtils.getJedis();
// redis lpush
Long len = 0l;
if( (len = jedis.rpush(listKey(), "1").longValue()) == 1) { //说明当前没有锁
//jedis.rpush(listKey(), "1");
positionLocal.set(0);
} else {
//说明当前已经有线程在等待锁
System.out.println(len);
positionLocal.set( (new Long(len -1 )).intValue());
while(jedis.lindex(listKey(), len - 2 ).equals("1")) {//等于1,该进程自旋等待
//System.out.println(Thread.currentThread().getName() + " 自旋等待");
}
}

System.out.println(Thread.currentThread().getName() + " 获取锁");
} finally {
RedisUtils.returnResource(jedis);
}

}

@Override
public void unlock() {
System.out.println(Thread.currentThread().getName() + " 尝试释放锁");
Integer pos = positionLocal.get();
Jedis jedis = null;
try {
jedis = RedisUtils.getJedis();
jedis.lset(listKey(), pos, "0");
} finally {
RedisUtils.returnResource(jedis);
}
System.out.println(Thread.currentThread().getName() + " 释放锁");

}



private String listKey() {
return keyprix + LIST_KEY;
}


}

 

 

 

//附上RedisUtils 源码

package persistent.prestige.redis;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

public class RedisUtils {

// Redis服务器IP
//private static String ADDR = "10.88.7.3";
private static String ADDR = "192.168.1.103";


// Redis的端口号
private static int PORT = 6379;

// 访问密码
private static String AUTH = "admin";

// 可用连接实例的最大数目,默认值为8;
// 如果赋值为-1,则表示不限制;如果pool已经分配了maxActive个jedis实例,则此时pool的状态为exhausted(耗尽)。
private static int MAX_ACTIVE = 1024;

// 控制一个pool最多有多少个状态为idle(空闲的)的jedis实例,默认值也是8。
private static int MAX_IDLE = 200;

// 等待可用连接的最大时间,单位毫秒,默认值为-1,表示永不超时。如果超过等待时间,则直接抛出JedisConnectionException;
private static int MAX_WAIT = 10000;

private static int TIMEOUT = 10000;

// 在borrow一个jedis实例时,是否提前进行validate操作;如果为true,则得到的jedis实例均是可用的;
private static boolean TEST_ON_BORROW = true;

private static JedisPool jedisPool = null;

/**
* 初始化Redis连接池
*/
static {
try {
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxIdle(MAX_IDLE);
config.setTestOnBorrow(TEST_ON_BORROW);
config.setMaxIdle(200);
//最大连接数, 应用自己评估,不要超过AliCloudDB for Redis每个实例最大的连接数
config.setMaxTotal(300);
config.setTestOnBorrow(false);
config.setTestOnReturn(false);



jedisPool = new JedisPool(config, ADDR, PORT, TIMEOUT);
} catch (Exception e) {
e.printStackTrace();
}
}

/**
* 获取Jedis实例
*
* @return
*/
public synchronized static Jedis getJedis() {
try {
if (jedisPool != null) {
Jedis resource = jedisPool.getResource();
return resource;
} else {
return null;
}
} catch (Exception e) {
e.printStackTrace();
return null;
}
}

public static void returnResource(final Jedis jedis) {
if (jedis != null) {
jedisPool.returnResource(jedis);
}
}

public static void main(String[] args) {
// TODO Auto-generated method stub
Jedis jedis = null;
try {
jedis = RedisUtils.getJedis();
String key = "persistent:prestige:redis:lock:ReentrantLock:list";
System.out.println(jedis.lindex(key, 0 ).equals("0"));

} finally {
RedisUtils.returnResource(jedis);
}
}

}

转载于:https://www.cnblogs.com/dingwmz/p/5665965.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值