利用redis实现分布式锁(3) ——具体实现方式二
利用redis实现分布式锁(三) ——具体实现方式二
import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.UUID; import java.util.concurrent.TimeUnit; /** * 分布式锁 * * @Author guweiqiang */ public class DistributedLock { private static final Logger logger = LoggerFactory.getLogger(DistributedLock.class); private static final String LOCK_PREFIX = "SHP:LOCK:"; private static final long DEFAULT_SLEEP_TIME = 100; /** * key值 */ private String lockKey; /** * value值,保证唯一 */ private String value = UUID.randomUUID().toString(); /** * 有效期,单位:毫秒 */ private long expireTime; /** * 是否获得锁 */ private boolean locked = false; /** * 功能描述:构造函数 * * @param shardedJedisClient shardedJedis客户端 * @param lockKey key值 * @param expireTime 有效期,单位:毫秒 * @Author gy * @Date 2016年8月14日下午6:10:49 */ public DistributedLock(String lockKey, long expireTime) { this.lockKey = LOCK_PREFIX + lockKey; this.expireTime = expireTime; } /** * 功能描述: 获取阻塞锁,如果锁空闲立即返回 ,获取失败 一直重试 * * @param sleepTime 线程sleep时间,单位:毫秒 * @throws InterruptedException * @Author gy * @Date 2016年8月14日下午9:12:40 */ public void lock(long paramSleepTime) throws InterruptedException { long sleepTime = paramSleepTime; logger.info("lock expireTime is {} ",expireTime); if (sleepTime <= 0) { sleepTime = DEFAULT_SLEEP_TIME; } do { boolean flag = setnxpx(); if (flag) { locked = true; return; } Thread.sleep(sleepTime); } while (true); } /** * 功能描述: 获取立即返回锁,如果锁可用,立即返回true, 否则返回false * * @return 成功失败标志,true表示获取锁成功,false失败 * @Author gy * @Date 2016年8月14日下午9:06:23 */ public boolean tryLock() { return tryLock(0, 0); } /** * 功能描述:获取等待重试锁,锁在给定的超时时间内空闲,则获取锁成功 返回true, 否则返回false * * @param timeout 重试超时时间,单位:毫秒 * @param sleepTime 线程sleep时间,仅timeout大于0时有效,单位:毫秒 * @return 成功失败标志,true表示获取锁成功,false失败 * @Author gy * @Date 2016年8月14日下午9:01:13 */ public boolean tryLock(long timeout, long sleepTime) { long nano = System.nanoTime(); try { do { boolean flag = setnxpx(); if (flag) { locked = true; return true; } if (timeout <= 0 || sleepTime <= 0) { return false; } Thread.sleep(sleepTime); } while ((System.nanoTime() - nano) < TimeUnit.MILLISECONDS.toNanos(timeout)); } catch (Exception e) { logger.error("DistributedLock tryLock error:" + e.getMessage(), e); } return false; } /** * 功能描述: 释放锁 * * @Author gy * @Date 2016年8月14日下午7:51:20 */ public void unLock() { release(); } private boolean setnxpx() { Long result = JedisUtil.setnx(lockKey, value); if (result==1) { return true; } return false; } private void release() { if (locked) { // 获取redis中的值,验证是否与之前设置的值相等,如果相等,则删除,避免删除掉其他线程的锁 String tmp = JedisUtil.get(lockKey); if (value.equals(tmp)) { JedisUtil.del(lockKey); } locked = false; } } }
使用方法:
String key = "lockKey"; DistributedLock lock = new DistributedLock(key, 10000); // 超时10秒 if(!lock.tryLock()){ // 加锁失败,直接返回 responseBody.setResponseDto(0); return responseBody; } // 拿到锁之后,处理业务
JedisUtil工具类代码:
import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Set; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import redis.clients.jedis.Jedis; import redis.clients.jedis.MultiKeyCommands; import redis.clients.jedis.ShardedJedis; import com.suning.framework.sedis.ShardedJedisAction; import com.suning.framework.sedis.impl.ShardedJedisClientImpl; /** * 功能描述: jedis 2.0 数据连接池类 〈功能详细描述〉 * */ public class JedisUtil { private static final Logger LOGGER = LoggerFactory.getLogger(JedisUtil.class); private static ShardedJedisClientImpl jedisClient; // 初始化此实例 static { jedisClient = new ShardedJedisClientImpl("redis.conf"); } private JedisUtil() { } /** * 从Redis的SET结构中取出一个值 并删除此值 * * @param key key * @return * @see [相关类/方法](可选) * @since [产品/模块版本](可选) */ public static String spop(final String key) { return jedisClient.execute(new ShardedJedisAction<String>() { @Override public String doAction(ShardedJedis shardedJedis) { return shardedJedis.spop(key); } }); } /** * 从Redis的SET结构中取出多个值 * * @param key key * @return * @see [相关类/方法](可选) * @since [产品/模块版本](可选) */ public static Set<String> smembers(final String key) { return jedisClient.execute(new ShardedJedisAction<Set<String>>() { @Override public Set<String> doAction(ShardedJedis shardedJedis) { return shardedJedis.smembers(key); } }); } /** * 从Redis的SET结构中删除多个成员 * * @param key key * @return * @see [相关类/方法](可选) * @since [产品/模块版本](可选) */ public static Long srem(final String key, final String[] members) { return jedisClient.execute(new ShardedJedisAction<Long>() { @Override public Long doAction(ShardedJedis shardedJedis) { return shardedJedis.srem(key, members); } }); } /** * 将一个member 元素加入到集合key 当中,已经存在于集合的member 元素将被忽略。 假如 key 不存在,则创建一个只包含member 元素作成员的集合。 当key 不是集合类型时,返回一个错误。时间复杂度O(1) * * @param key * @param members * @return */ public static Long sadd(final String key, final String member) { try { return jedisClient.execute(new ShardedJedisAction<Long>() { public Long doAction(ShardedJedis jedis) { return jedis.sadd(key, member); } }); } catch (Exception e) { LOGGER.error("SNEcsJedisUtil.sadd error = ", e); return null; } } /** * 从Redis的String添加多个成员 * * @param key key * @return * @see [相关类/方法](可选) * @since [产品/模块版本](可选) */ public static String set(final String key, final String value, final int expireTime) { try { return jedisClient.execute(new ShardedJedisAction<String>() { @Override public String doAction(ShardedJedis shardedJedis) { String result = shardedJedis.set(key, value); shardedJedis.expire(key, expireTime); return result; } }); } catch (Exception e) { LOGGER.error("JedisUtil.set error = ", e); return null; } } /** * 将序列化对象值value关联到key,如果key已经持有其他值,SET就覆写旧值,无视类型 * * @param key * @param value * @return */ public static String set(final String key, final String value) { return jedisClient.execute(new ShardedJedisAction<String>() { public String doAction(ShardedJedis jedis) { return jedis.set(key, value); } }); } /** * 返回key所关联的序列化对象。如果key不存在则返回null * * @param key * @return */ public static String get(final String key) { try { return jedisClient.execute(new ShardedJedisAction<String>() { public String doAction(ShardedJedis jedis) { return jedis.get(key); } }); } catch (Exception e) { LOGGER.error("JedisUtil.get error = ", e); return null; } } /** * * 将给定 key 的值设为 value ,并返回 key 的旧值(old value)。key 不存在时,返回 null * * @param key * @param value * @return * @see [相关类/方法](可选) * @since [产品/模块版本](可选) */ public static String getSet(final String key, final String value) { return jedisClient.execute(new ShardedJedisAction<String>() { public String doAction(ShardedJedis jedis) { return jedis.getSet(key, value); } }); } /** * 〈一句话功能简述〉 〈功能详细描述〉 * * @param hash * @return * @see [相关类/方法](可选) * @since [产品/模块版本] (可选) */ public static String mset(final String... keysValues) { return jedisClient.execute(new ShardedJedisAction<String>() { public String doAction(ShardedJedis jedis) { if (jedis instanceof MultiKeyCommands) { MultiKeyCommands shardedJedis = (MultiKeyCommands) jedis; return shardedJedis.mset(keysValues); } return ""; } }); } /** * 批量返回一组Key所关联的序列化对象 * * @param keys * @return * @see [相关类/方法](可选) * @since [产品/模块版本] (可选) */ public static List<String> mget(final String... keys) { return jedisClient.execute(new ShardedJedisAction<List<String>>() { public List<String> doAction(ShardedJedis jedis) { if (jedis instanceof MultiKeyCommands) { MultiKeyCommands shardedJedis = (MultiKeyCommands) jedis; return shardedJedis.mget(keys); } return null; } }); } /** * 移除给定的key。如果key不存在,则忽略该命令。 * * @param key * @return */ public static Long del(final String key) { return jedisClient.execute(new ShardedJedisAction<Long>() { public Long doAction(ShardedJedis jedis) { return jedis.del(key); } }); } /** * 将哈希表key中的域field的值设为value。如果key不存在,一个新的哈希表被创建并 进行HSET操作。如果域field已经存在于哈希表中,旧值将被覆盖。 * * @param key field value * @return 如果field是哈希表中的一个新建域,并且值设置成功,返回1。如果哈希 表中域field已经存在且旧值已被新值覆盖,返回0。 */ public static Long hset(final String key, final String field, final String value) { return jedisClient.execute(new ShardedJedisAction<Long>() { public Long doAction(ShardedJedis jedis) { return jedis.hset(key, field, value); } }); } /** * 获取hash结构的元素个数。 * * @param key field value * @return */ public static Long hlen(final String key) { return jedisClient.execute(new ShardedJedisAction<Long>() { public Long doAction(ShardedJedis jedis) { return jedis.hlen(key); } }); } /** * 返回哈希表 key 中给定域 field 的值。 * * @param key field * @return 给定域的值。 当给定域不存在或是给定key不存在时,返回null。 */ public static String hget(final String key, final String field) { return jedisClient.execute(new ShardedJedisAction<String>() { public String doAction(ShardedJedis jedis) { return jedis.hget(key, field); } }); } /** * * 功能描述: 获取指定权重之间的成员 * 〈功能详细描述〉 * * @param key 指定的有序集合 * @param minScore 最小权重 * @param maxScore 最大权重 * @return * @see [相关类/方法](可选) * @since [产品/模块版本](可选) */ public static Set<String> zrangeByScore(final String key, final double minScore, final double maxScore) { return jedisClient.execute(new ShardedJedisAction<Set<String>>() { public Set<String> doAction(ShardedJedis jedis) { return jedis.zrangeByScore(key, minScore, maxScore); } }); } /** * 同时将多个域-值对设置到哈希表key中。如果key不存在,一个空哈希表被创建并执行 HMSET操作。 时间复杂度O(N),N为域-值对的数量。 * * @param key hash * @return */ public static String hmset(final String key, final Map<String, String> hash) { return jedisClient.execute(new ShardedJedisAction<String>() { public String doAction(ShardedJedis jedis) { return jedis.hmset(key, hash); } }); } /** * 〈一句话功能简述〉 〈功能详细描述〉 * * @param key * @param fields * @return * @see [相关类/方法](可选) * @since [产品/模块版本] (可选) */ public static List<String> hmget(final String key, final String[] filedString) { return jedisClient.execute(new ShardedJedisAction<List<String>>() { public List<String> doAction(ShardedJedis jedis) { return jedis.hmget(key, filedString); } }); } /** * 删除哈希表key中的指定域,不存在的域将被忽略。 * * @param key field * @return */ public static Long hdel(final String key, final String... field) { return jedisClient.execute(new ShardedJedisAction<Long>() { public Long doAction(ShardedJedis jedis) { return jedis.hdel(key, field); } }); } public static Boolean hexists(final String key, final String field) { return jedisClient.execute(new ShardedJedisAction<Boolean>() { public Boolean doAction(ShardedJedis jedis) { return jedis.hexists(key, field); } }); } public static Boolean exists(final String key) { return jedisClient.execute(new ShardedJedisAction<Boolean>() { public Boolean doAction(ShardedJedis jedis) { return jedis.exists(key); } }); } public static Long rpush(final String key, final String member) { return jedisClient.execute(new ShardedJedisAction<Long>() { public Long doAction(ShardedJedis jedis) { return jedis.rpush(key, member); } }); } /** * 向list的头添加记录 * * @param key * @param member 被添加的值 * @return */ public static Long lpush(final String key, final String member) { try { return jedisClient.execute(new ShardedJedisAction<Long>() { public Long doAction(ShardedJedis jedis) { return jedis.lpush(key, member); } }); } catch (Exception e) { LOGGER.error("JedisUtil.lpush error = ", e); return null; } } /** * 保留list的start和end之间的数据,其他删除 * * @param key * @param start 起始位置 * @param end 结束位置 * @return */ public static String ltrim(final String key, final long start, final long end) { try { return jedisClient.execute(new ShardedJedisAction<String>() { public String doAction(ShardedJedis jedis) { return jedis.ltrim(key, start, end); } }); } catch (Exception e) { LOGGER.error("JedisUtil.ltrim error = ", e); return null; } } /** * 删除count个指定value * * @param key * @param count 个数 * @param value 被删的值 * @return */ public static Long lrem(final String key, final long count, final String value) { try { return jedisClient.execute(new ShardedJedisAction<Long>() { public Long doAction(ShardedJedis jedis) { return jedis.lrem(key, count, value); } }); } catch (Exception e) { LOGGER.error("JedisUtil.lrem error = ", e); return null; } } /** * 查询list * * @param key * @return */ public static List<String> lrange(final String key) { try { return jedisClient.execute(new ShardedJedisAction<List<String>>() { public List<String> doAction(ShardedJedis jedis) { return jedis.lrange(key, 0, -1); } }); } catch (Exception e) { LOGGER.error("JedisUtil.lrange error = ", e); } return new ArrayList<String>(); } public static Set<String> hkeys(final String key) { return jedisClient.execute(new ShardedJedisAction<Set<String>>() { public Set<String> doAction(ShardedJedis jedis) { return jedis.hkeys(key); } }); } /** * 为哈希表 key 中的域 field 的值加上增量 increment 。 增量也可以为负数,相当于对给定域进行减法操作。 如果 key 不存在,一个新的哈希表被创建并执行 HINCRBY 命令。 如果域 field * 不存在,那么在执行命令前,域的值被初始化为 0 。 对一个储存字符串值的域 field 执行 HINCRBY 命令将造成一个错误。 本操作的值被限制在 64 位(bit)有符号数字表示之内。 * * @param key * @param field * @param increment * @return 执行 hincrBy 命令之后,哈希表 key 中域 field 的值 */ public static Long hincrBy(final String key, final String field, final long increment) { return jedisClient.execute(new ShardedJedisAction<Long>() { public Long doAction(ShardedJedis jedis) { return jedis.hincrBy(key, field, increment); } }); } /** * 为给定key设置失效时刻,当key过期时,它会被自动删除 时间复杂度O(1) * * @param key * @param unixTime Unix时间戳,单位为秒,使用时考虑误差 * @return 1:成功;0:key不存在或不能为key设置失效时刻 */ public static Long expireAt(final String key, final long unixTime) { return jedisClient.execute(new ShardedJedisAction<Long>() { public Long doAction(ShardedJedis jedis) { return jedis.expireAt(key, unixTime); } }); } public static Long hsetnx(final String key, final String field, final String value) { return jedisClient.execute(new ShardedJedisAction<Long>() { public Long doAction(ShardedJedis jedis) { return jedis.hsetnx(key, field, value); } }); } public static Map<String, String> hgetAll(final String key) { return jedisClient.execute(new ShardedJedisAction<Map<String, String>>() { public Map<String, String> doAction(ShardedJedis jedis) { return jedis.hgetAll(key); } }); } /** * 为给定key设置生存时间,当key过期时,它会被自动删除 * * @param key * @param seconds 秒 * @return 1:成功;0:key不存在或不能为key设置生存时间时 */ public static Long expire(final String key, final int seconds) { return jedisClient.execute(new ShardedJedisAction<Long>() { public Long doAction(ShardedJedis jedis) { return jedis.expire(key, seconds); } }); } /** * @param arg0 * @param arg1 * @param arg2 * @return * @see redis.clients.jedis.JedisCommands#setex(java.lang.String, int, java.lang.String) */ public static String setex(final String key, final int field, final String value) { return jedisClient.execute(new ShardedJedisAction<String>() { public String doAction(ShardedJedis jedis) { return jedis.setex(key, field, value); } }); } /** * @param arg0 * @return * @see redis.clients.jedis.JedisCommands#incr(java.lang.String) */ public static Long incr(final String arg0) { return jedisClient.execute(new ShardedJedisAction<Long>() { public Long doAction(ShardedJedis jedis) { return jedis.incr(arg0); } }); } /** * @param arg0 * @return * @see redis.clients.jedis.JedisCommands#incr(java.lang.String) */ public static Long decr(final String arg0) { return jedisClient.execute(new ShardedJedisAction<Long>() { public Long doAction(ShardedJedis jedis) { return jedis.decr(arg0); } }); } /** * @param arg0 * @return * @see redis.clients.jedis.JedisCommands#incr(java.lang.String) */ public static Set<String> zrevrange(final String key, final long start, final long end) { return jedisClient.execute(new ShardedJedisAction<Set<String>>() { public Set<String> doAction(ShardedJedis jedis) { return jedis.zrevrange(key, start, end); } }); } /** * @param arg0 * @return * @see redis.clients.jedis.JedisCommands#incr(java.lang.String) */ public static Set<String> zrange(final String key, final long start, final long end) { return jedisClient.execute(new ShardedJedisAction<Set<String>>() { public Set<String> doAction(ShardedJedis jedis) { return jedis.zrange(key, start, end); } }); } /** * @param arg0 * @return * @see redis.clients.jedis.JedisCommands#incr(java.lang.String) */ public static Double zscore(final String key, final String member) { return jedisClient.execute(new ShardedJedisAction<Double>() { public Double doAction(ShardedJedis jedis) { return jedis.zscore(key, member); } }); } /** * @param arg0 * @return * @see redis.clients.jedis.JedisCommands#incr(java.lang.String) */ public static Long zcard(final String key) { return jedisClient.execute(new ShardedJedisAction<Long>() { public Long doAction(ShardedJedis jedis) { return jedis.zcard(key); } }); } /** * @param arg0 * @return * @see redis.clients.jedis.JedisCommands#incr(java.lang.String) */ public static Long zadd(final String key, final double score, final String member) { return jedisClient.execute(new ShardedJedisAction<Long>() { public Long doAction(ShardedJedis jedis) { return jedis.zadd(key, score, member); } }); } /** * @param arg0 * @return * @see redis.clients.jedis.JedisCommands#incr(java.lang.String) */ public static Long zremrangeByRank(final String key, final long start, final long end) { return jedisClient.execute(new ShardedJedisAction<Long>() { public Long doAction(ShardedJedis jedis) { return jedis.zremrangeByRank(key, start, end); } }); } /** * @param arg0 * @return * @see redis.clients.jedis.JedisCommands#incr(java.lang.String) */ public static Long zrem(final String key, final String... members) { return jedisClient.execute(new ShardedJedisAction<Long>() { public Long doAction(ShardedJedis jedis) { return jedis.zrem(key, members); } }); } /** * 功能描述: 随机获取集合中的元素<br> * * @param key * @param count * @return * @see [相关类/方法](可选) * @since [产品/模块版本](可选) */ public static List<String> srandmember(final String key, final int count) { try { return jedisClient.execute(new ShardedJedisAction<List<String>>() { public List<String> doAction(ShardedJedis jedis) { Jedis j = jedis.getShard(key); return j.srandmember(key, count); } }); } catch (Exception e) { LOGGER.error("JedisUtil.srandmember error = ", e); return null; } } /** * 从Redis的SET结构中删除成员 * * @param key key * @return * @see [相关类/方法](可选) * @since [产品/模块版本](可选) */ public static Long srem(final String key, final String members) { try { return jedisClient.execute(new ShardedJedisAction<Long>() { @Override public Long doAction(ShardedJedis shardedJedis) { return shardedJedis.srem(key, members); } }); } catch (Exception e) { LOGGER.error("JedisUtil.srem error = ", e); return null; } } /** * 将给定 key 的值设为 value ,如果key不存在时,返回1,否则返回失败 * @param key * @param value * @return */ public static Long setnx(final String key, final String value){ return jedisClient.execute(new ShardedJedisAction<Long>() { public Long doAction(ShardedJedis jedis) { return jedis.setnx(key, value); } }); } }