Redis分布式锁,阻塞线程

  • 时间:
  • 浏览:0
  • 来源:跟我学网络

最后发布:2018-07-31 20:13:06首次发布:2018-07-31 20:13:06

/**
 * @author : tangjiabin
 * @date 2018/7/2 15:03
 */
@Slf4j
@Service
public class RedisLock {

  @Autowired
  private StringRedisTemplate redisTemplate;

  public static final String REDIS_LOCK = "RedisLock:";


  /**
   * 5s 锁的超时时间
   */
  private static final long DEFAULT_WAIT_LOCK_TIME_OUT = 5;
  /**
   * 10s锁的有效时间
   */
  private static final long DEFAULT_EXPIRE = 10;

  /**
   * 获取锁
   *
   * @param key
   * @return : boolean
   * @author : tangjiabin
   * @date 2018/7/2 15:46
   */
  public boolean lock(String key) {
    return lock(key, DEFAULT_WAIT_LOCK_TIME_OUT, TimeUnit.SECONDS);
  }

  /**
   * 释放锁
   *
   * @param key
   * @return : void
   * @author : tangjiabin
   * @date 2018/7/2 15:42
   */
  public void unlock(String key) {
    RedisConnection connection = null;
    try {
      String lockKey = generateLockKey(key);
      connection = redisTemplate.getConnectionFactory().getConnection();
      connection.del(lockKey.getBytes());
    } catch (Exception e) {
      log.error("{}", e.getMessage(), e);
    }finally {
      //一定要关闭连接,不然会导致连接一直不释放
      connection.close();
    }
  }

  /**
   * 组装锁的key
   *
   * @param key
   * @return : java.lang.String
   * @author : tangjiabin
   * @date 2018/7/2 15:46
   */
  private String generateLockKey(String key) {
    return String.format(REDIS_LOCK + "%s", key);
  }

  /**
   * 获取锁
   *
   * @param key
   * @param timeout
   * @param seconds
   * @return : boolean
   * @author : tangjiabin
   * @date 2018/7/2 15:42
   */
  public boolean lock(String key, long timeout, TimeUnit seconds) {
    String lockKey = generateLockKey(key);
    long nanoWaitForLock = seconds.toNanos(timeout);
    long start = System.nanoTime();
    RedisConnection connection = null;
    try {
      connection = redisTemplate.getConnectionFactory().getConnection();
      while ((System.nanoTime() - start) < nanoWaitForLock) {
        if (connection.setNX(lockKey.getBytes(), new byte[0])) {
          //暂设置为80s过期,防止异常中断锁未释放
          redisTemplate.expire(lockKey, DEFAULT_EXPIRE, TimeUnit.SECONDS);
          if (log.isDebugEnabled()) {
            log.debug("add RedisLock[{}].{}", key, Thread.currentThread());
          }
          return true;
        }
        //加随机时间防止活锁
        TimeUnit.MILLISECONDS.sleep(1000 + new Random().nextInt(100));
      }
    } catch (Exception e) {
      log.error("{}", e.getMessage(), e);
      unlock(key);
    } finally {
      //一定要关闭连接,不然会导致连接一直不释放
      connection.close();
    }
    return false;
  }


}