在项目开发中,常常会碰到需要做lock锁的操作,而Redis又是最常用的分布式锁。在这提供一种简单的分布式锁实现,当然这里也有些考虑不周到,比如没实现公平与非公平锁、重入特性以及setNx及expire命令是分开的在极端(比如执行完A命令程序被kill -9了)造成死锁情况,没做redis集群情况下的高可用。
@Componentpublic class RedisOperation { @Autowired private RedisTemplate redisTemplate; private static final long DEFAULT_EXPIRATION_TIMES = 600l; public void set(final String key, final String value) { this.set(key, value, DEFAULT_EXPIRATION_TIMES); } public void set(final String key, final String value, final long seconds) { redisTemplate.execute(new RedisCallback() { @Override public Object doInRedis(RedisConnection connection) throws DataAccessException { connection.setEx(redisTemplate.getStringSerializer().serialize(key), seconds, redisTemplate.getStringSerializer().serialize(value)); return null; } }); } public boolean setNx(final String key, final String value, final long seconds) { return redisTemplate.execute(new RedisCallback
() { @Override public Boolean doInRedis(RedisConnection connection) throws DataAccessException { byte[] serializeKey = redisTemplate.getStringSerializer().serialize(key); boolean result = connection.setNX(serializeKey, redisTemplate.getStringSerializer().serialize(value)); if (result) { connection.expire(serializeKey, seconds); } return result; } }); } public String get(final String key) { return redisTemplate.execute(new RedisCallback
() { @Override public String doInRedis(RedisConnection connection) throws DataAccessException { byte[] byteKye = redisTemplate.getStringSerializer().serialize(key); if (connection.exists(byteKye)) { byte[] byteValue = connection.get(byteKye); String value = redisTemplate.getStringSerializer().deserialize(byteValue); return value; } return null; } }); } public boolean exists(final String key) { return redisTemplate.execute(new RedisCallback
() { @Override public Boolean doInRedis(RedisConnection connection) throws DataAccessException { return connection.exists(redisTemplate.getStringSerializer().serialize(key)); } }); } public void delete(final String key) { redisTemplate.execute(new RedisCallback
() { @Override public Object doInRedis(RedisConnection connection) throws DataAccessException { connection.del(redisTemplate.getStringSerializer().serialize(key)); return null; } }); }}@Componentpublic class DistributeLock { private static final Logger logger = LoggerFactory.getLogger(DistributeLock.class); public static final String REDIS_LOCK = "Demo:RedisLock:"; @Autowired private RedisOperation redisOperation; public boolean lock(String key, long timeout, long waitTimeout) { return lock(key, timeout, waitTimeout, true); } /** * * @param key * @param timeout key超时时间 单位:秒 * @param waitTimeout 等待获取锁时间 单位:毫秒 * @param force 是否强依赖锁 * @return * * @author hz15041240 * @date 2017-8-30 下午5:20:14 * @version */ public boolean lock(String key, long timeout, long waitTimeout, boolean forced) { String lockKey = generateLockKey(key); long nanoWaitForLock = TimeUnit.MILLISECONDS.toNanos(waitTimeout); long start = System.nanoTime(); try { do { if (redisOperation.setNx(lockKey, key, timeout)) { logger.debug("add distributed lock succeed; lockKey:{}", lockKey); return true; } TimeUnit.MILLISECONDS.sleep(RandomUtils.nextInt(10, 80)); } while ((System.nanoTime() - start) < nanoWaitForLock); } catch (Exception e) { logger.error(String.format("add distributed lock exception lockKey:%s", lockKey), e); unlock(lockKey); return !forced; } return false; } public void unlock(String key) { String lockKey = generateLockKey(key); try { redisOperation.delete(lockKey); logger.debug("remove distributed lock key:{} succeed", lockKey); } catch (Exception e) { logger.error(String.format("unlock exception lockKey:{} ", lockKey), e); } } public boolean isLock(String key) { String lockKey = generateLockKey(key); return redisOperation.exists(lockKey); } private String generateLockKey(String key) { return new StringBuilder(50).append(REDIS_LOCK).append(key).toString(); }}