您的位置:首页 > 数据库 > Redis

Redis并发锁控制

2016-04-15 15:06 405 查看
为了防止用户在页面上重复点击或者同时发起多次请求,请求处理需要操作redis缓存,这个时候需要对并发边界进行并发锁控制,实现思路:

由于每个页面发起的请求带的token具备唯一性,可以将token作为锁(key),当前时间作为value进行并发锁控制,分为两个方法:acquireLock和realeaseLock

/**尝试获取锁并设置有效时间*/
53
+    public boolean acquireLock(String lock, long expired){
54
+        boolean isSuccess = false;
55
+        Jedis jedis = jedisPool.getResource();
56
+        long value = System.currentTimeMillis() + expired + 1;
57
+        long acquired = jedis.setnx(lock, String.valueOf(value));
58
+        if (acquired == 1)
59
+            isSuccess = true;
60
+        else {
61
+            long oldValue = Long.valueOf(jedis.get(lock));
62
+            //如果其他资源之前获得锁已经超时
63
+            if (oldValue < System.currentTimeMillis()){
64
+                String getValue = jedis.getSet(lock, String.valueOf(value));
65
+                if (Long.valueOf(getValue) == oldValue)
66
+                    isSuccess = true;
67
+                else
68
+                    isSuccess = false;
69
+            }
70
+            else isSuccess = false;
71
+        }
72
+        jedisPool.returnResource(jedis);
73
+        return isSuccess;
74
+    }
75
+
76
+    /**释放锁资源*/
77
+    public void releaseLock(String lock){
78
+        Jedis jedis = jedisPool.getResource();
79
+        long currentTime = System.currentTimeMillis();
80
+        if (currentTime < Long.valueOf(jedis.get(lock))){
81
+            jedis.del(lock);
82
+        }
83
+        jedisPool.returnResource(jedis);
84
+    }


经过代码review,对照开源的jedisLock源码,发现以上实现逻辑问题在于,对于jedisPool.getResource如果发生异常,没有对异常进行处理,在外面包装类加上如下处理:

Object runTask(Callback callback) {
Jedis jedis = null;
boolean broken = false;
try {
jedis = jedisPool.getResource();
return callback.onTask(jedis);
} catch (JedisException e) {
broken = handleJedisException(e);
} catch (Exception e) {
log.error("Redis runTask error: ", e);
} finally {
closeResource(jedis, broken);
jedis = null;
}
return null;
}


private boolean handleJedisException(JedisException jedisException) {
if (jedisException instanceof JedisConnectionException) {
log.error("Redis connection lost.", jedisException);
} else if (jedisException instanceof JedisDataException) {
if ((jedisException.getMessage() != null) && (jedisException.getMessage().indexOf("READONLY") != -1)) {
log.error("Redis connection are read-only slave.", jedisException);
} else {
// dataException, isBroken=false
return false;
}
} else {
log.error("Jedis exception happen.", jedisException);
}
return true;
}


private void closeResource(Jedis jedis, boolean conectionBroken) {
try {
if (conectionBroken) {
jedisPool.returnBrokenResource(jedis);
} else {
jedisPool.returnResource(jedis);
}
} catch (Exception e) {
log.error("return back jedis failed, will fore close the jedis.", e);
jedis.close();
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: