JAVA 分布式环境 Redis互斥锁

  开始的时候项目没有添加互斥锁,用的依然是老的思路,在并发量增加的情况下,遇到了很多的问题,包括数据库重复读等,想了下考虑增加 互斥锁来排序对单个资源的操作。

  

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Order(1)
public @interface DistributeLock {
    LockType type() default LockType.Id;

    enum LockType {
        Id,
        Function;
    }
}

    实现了两个方式,用注解+Aspect的方式 和 try(Closeable){} 的方式确保锁的释放。

    实现依托于redis的 

String result = conn.set(key, value, "NX", "PX", expire);
  方法,该方法在单节点和集群下都可用。我测试用的单节点生产cluster集群都测试通过。
  
  
public class MutexLock implements Closeable {
    RedisCache redisCache;
    //
    private boolean isWorkFine = false;
    private String key;
    private final String DEFAULT_PREFIX = "DEFAULT";

    public boolean isWorkFine() {
        return isWorkFine;
    }

    public MutexLock(String prefix, Long id) throws EirException{
        redisCache = ApplicationContextHelper.getBean(RedisCache.class);
        if (redisCache == null) {
            System.out.println("枷锁 redis 未开启");
            return;
        }
        this.key = (StringUtil.isNullOrEmpty(prefix) ? DEFAULT_PREFIX : prefix) + ":" + id;
        Boolean tryGetLock = new RedisUtils(redisCache).setnx(key);
        if (tryGetLock != null && tryGetLock) {
            isWorkFine = true;
        }
        if (tryGetLock != null && !tryGetLock) {
            throw new EirException("当前资源正忙");
        }
    }

    /**
     * Closes this stream and releases any system resources associated
     * with it. If the stream is already closed then invoking this
     * method has no effect.
     * <p>
     * <p> As noted in {@link AutoCloseable#close()}, cases where the
     * close may fail require careful attention. It is strongly advised
     * to relinquish the underlying resources and to internally
     * <em>mark</em> the {@code Closeable} as closed, prior to throwing
     * the {@code IOException}.
     *
     * @throws IOException if an I/O error occurs
     */
    @Override
    public void close() {
        try {
            if (isWorkFine) {
                new RedisUtils(redisCache).releaseLock(this.key);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

 

  redisUtils 中在getLock的时候 设置了等待时间,5秒钟,超过之后会返回“资源正忙”, 锁也加了超时时间, 避免死锁问题。

测试代码就不贴了。
  

  总结下来这个应该是最廉价实惠的互斥锁方案了。

  

posted @ 2018-12-17 14:05  LiMng06  阅读(918)  评论(0)    收藏  举报