标签:
为了防止用户在页面上重复点击或者同时发起多次请求,请求处理需要操作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(); } }
标签:
原文地址:http://www.cnblogs.com/harlenzhang/p/5395568.html