cfsky 发表于 2015-7-20 10:34:06

Redis实现分布式锁

  /**
* @author http://blog.iyunv.com/java2000_wl
* @version 1.0.0
*/
public class RedisBillLockHandler implements IBatchBillLockHandler {
    private static final Logger LOGGER = LoggerFactory.getLogger(RedisBillLockHandler.class);
    private static final int DEFAULT_SINGLE_EXPIRE_TIME = 3;
   
    private static final int DEFAULT_BATCH_EXPIRE_TIME = 6;
    private final JedisPool jedisPool;
   
    /**
   * 构造
   * @author http://blog.iyunv.com/java2000_wl
   */
    public RedisBillLockHandler(JedisPool jedisPool) {
      this.jedisPool = jedisPool;
    }
    /**
   * 获取锁如果锁可用   立即返回true,否则返回false
   * @author http://blog.iyunv.com/java2000_wl
   * @see com.fx.platform.components.lock.IBillLockHandler#tryLock(com.fx.platform.components.lock.IBillIdentify)
   * @param billIdentify
   * @return
   */
    public boolean tryLock(IBillIdentify billIdentify) {
      return tryLock(billIdentify, 0L, null);
    }
    /**
   * 锁在给定的等待时间内空闲,则获取锁成功 返回true, 否则返回false
   * @author http://blog.iyunv.com/java2000_wl
   * @see com.fx.platform.components.lock.IBillLockHandler#tryLock(com.fx.platform.components.lock.IBillIdentify,
   *      long, java.util.concurrent.TimeUnit)
   * @param billIdentify
   * @param timeout
   * @param unit
   * @return
   */
    public boolean tryLock(IBillIdentify billIdentify, long timeout, TimeUnit unit) {
      String key = (String) billIdentify.uniqueIdentify();
      Jedis jedis = null;
      try {
            jedis = getResource();
            long nano = System.nanoTime();
            do {
                LOGGER.debug("try lock key: " + key);
                Long i = jedis.setnx(key, key);
                if (i == 1) {
                  jedis.expire(key, DEFAULT_SINGLE_EXPIRE_TIME);
                  LOGGER.debug("get lock, key: " + key + " , expire in " + DEFAULT_SINGLE_EXPIRE_TIME + " seconds.");
                  return Boolean.TRUE;
                } else { // 存在锁
                  if (LOGGER.isDebugEnabled()) {
                        String desc = jedis.get(key);
                        LOGGER.debug("key: " + key + " locked by another business:" + desc);
                  }
                }
                if (timeout == 0) {
                  break;
                }
                Thread.sleep(300);
            } while ((System.nanoTime() - nano) < unit.toNanos(timeout));
            return Boolean.FALSE;
      } catch (JedisConnectionException je) {
            LOGGER.error(je.getMessage(), je);
            returnBrokenResource(jedis);
      } catch (Exception e) {
            LOGGER.error(e.getMessage(), e);
      } finally {
            returnResource(jedis);
      }
      return Boolean.FALSE;
    }
    /**
   * 如果锁空闲立即返回   获取失败 一直等待
   * @author http://blog.iyunv.com/java2000_wl
   * @see com.fx.platform.components.lock.IBillLockHandler#lock(com.fx.platform.components.lock.IBillIdentify)
   * @param billIdentify
   */
    public void lock(IBillIdentify billIdentify) {
      String key = (String) billIdentify.uniqueIdentify();
      Jedis jedis = null;
      try {
            jedis = getResource();
            do {
                LOGGER.debug("lock key: " + key);
                Long i = jedis.setnx(key, key);
                if (i == 1) {
                  jedis.expire(key, DEFAULT_SINGLE_EXPIRE_TIME);
                  LOGGER.debug("get lock, key: " + key + " , expire in " + DEFAULT_SINGLE_EXPIRE_TIME + " seconds.");
                  return;
                } else {
                  if (LOGGER.isDebugEnabled()) {
                        String desc = jedis.get(key);
                        LOGGER.debug("key: " + key + " locked by another business:" + desc);
                  }
                }
                Thread.sleep(300);
            } while (true);
      } catch (JedisConnectionException je) {
            LOGGER.error(je.getMessage(), je);
            returnBrokenResource(jedis);
      } catch (Exception e) {
            LOGGER.error(e.getMessage(), e);
      } finally {
            returnResource(jedis);
      }
    }
    /**
   * 释放锁
   * @author http://blog.iyunv.com/java2000_wl
   * @see com.fx.platform.components.lock.IBillLockHandler#unLock(com.fx.platform.components.lock.IBillIdentify)
   * @param billIdentify
   */
    public void unLock(IBillIdentify billIdentify) {
      List list = new ArrayList();
      list.add(billIdentify);
      unLock(list);
    }
    /**
   * 批量获取锁如果全部获取   立即返回true, 部分获取失败 返回false
   * @author http://blog.iyunv.com/java2000_wl
   * @date 2013-7-22 下午10:27:44
   * @see com.fx.platform.components.lock.IBatchBillLockHandler#tryLock(java.util.List)
   * @param billIdentifyList
   * @return
   */
    public boolean tryLock(List billIdentifyList) {
      return tryLock(billIdentifyList, 0L, null);
    }
   
    /**
   * 锁在给定的等待时间内空闲,则获取锁成功 返回true, 否则返回false
   * @author http://blog.iyunv.com/java2000_wl
   * @param billIdentifyList
   * @param timeout
   * @param unit
   * @return
   */
    public boolean tryLock(List billIdentifyList, long timeout, TimeUnit unit) {
      Jedis jedis = null;
      try {
            List needLocking = new CopyOnWriteArrayList();   
            List locked = new CopyOnWriteArrayList();   
            jedis = getResource();
            long nano = System.nanoTime();
            do {
                // 构建pipeline,批量提交
                Pipeline pipeline = jedis.pipelined();
                for (IBillIdentify identify : billIdentifyList) {
                  String key = (String) identify.uniqueIdentify();
                  needLocking.add(key);
                  pipeline.setnx(key, key);
                }
                LOGGER.debug("try lock keys: " + needLocking);
                // 提交redis执行计数
                List results = pipeline.syncAndReturnAll();
                for (int i = 0; i < results.size(); ++i) {
                  Long result = (Long) results.get(i);
                  String key = needLocking.get(i);
                  if (result == 1) {    // setnx成功,获得锁
                        jedis.expire(key, DEFAULT_BATCH_EXPIRE_TIME);
                        locked.add(key);
                  }
                }
                needLocking.removeAll(locked);    // 已锁定资源去除
               
                if (CollectionUtils.isEmpty(needLocking)) {
                  return true;
                } else {   
                  // 部分资源未能锁住
                  LOGGER.debug("keys: " + needLocking + " locked by another business:");
                }
               
                if (timeout == 0) {   
                  break;
                }
                Thread.sleep(500);   
            } while ((System.nanoTime() - nano) < unit.toNanos(timeout));
            // 得不到锁,释放锁定的部分对象,并返回失败
            if (!CollectionUtils.isEmpty(locked)) {
                jedis.del(locked.toArray(new String));
            }
            return false;
      } catch (JedisConnectionException je) {
            LOGGER.error(je.getMessage(), je);
            returnBrokenResource(jedis);
      } catch (Exception e) {
            LOGGER.error(e.getMessage(), e);
      } finally {
            returnResource(jedis);
      }
      return true;
    }
    /**
   * 批量释放锁
   * @author http://blog.iyunv.com/java2000_wl
   * @see com.fx.platform.components.lock.IBatchBillLockHandler#unLock(java.util.List)
   * @param billIdentifyList
   */
    public void unLock(List billIdentifyList) {
      List keys = new CopyOnWriteArrayList();
      for (IBillIdentify identify : billIdentifyList) {
            String key = (String) identify.uniqueIdentify();
            keys.add(key);
      }
      Jedis jedis = null;
      try {
            jedis = getResource();
            jedis.del(keys.toArray(new String));
            LOGGER.debug("release lock, keys :" + keys);
      } catch (JedisConnectionException je) {
            LOGGER.error(je.getMessage(), je);
            returnBrokenResource(jedis);
      } catch (Exception e) {
            LOGGER.error(e.getMessage(), e);
      } finally {
            returnResource(jedis);
      }
    }
   
    /**
   * @author http://blog.iyunv.com/java2000_wl
   * @date 2013-7-22 下午9:33:45
   * @return
   */
    private Jedis getResource() {
      return jedisPool.getResource();
    }
   
    /**
   * 销毁连接
   * @author http://blog.iyunv.com/java2000_wl
   * @param jedis
   */
    private void returnBrokenResource(Jedis jedis) {
      if (jedis == null) {
            return;
      }
      try {
            //容错
            jedisPool.returnBrokenResource(jedis);
      } catch (Exception e) {
            LOGGER.error(e.getMessage(), e);
      }
    }
   
    /**
   * @author http://blog.iyunv.com/java2000_wl
   * @param jedis
   */
    private void returnResource(Jedis jedis) {
      if (jedis == null) {
            return;
      }
      try {
            jedisPool.returnResource(jedis);
      } catch (Exception e) {
            LOGGER.error(e.getMessage(), e);
      }
    }
页: [1]
查看完整版本: Redis实现分布式锁