直接上代码
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