|
@@ -0,0 +1,493 @@
|
|
|
+package com.persagy.common.redis.template;
|
|
|
+
|
|
|
+import com.alibaba.fastjson.JSONObject;
|
|
|
+import com.persagy.common.constant.CommonConstant;
|
|
|
+import com.persagy.common.exception.LockException;
|
|
|
+import com.persagy.common.redis.base.RedissonTemplate;
|
|
|
+import com.persagy.common.redis.boot.RedisBeanContext;
|
|
|
+import org.redisson.api.RLock;
|
|
|
+import org.redisson.api.RedissonClient;
|
|
|
+import org.springframework.data.redis.connection.RedisStringCommands;
|
|
|
+import org.springframework.data.redis.core.*;
|
|
|
+import org.springframework.data.redis.core.script.RedisScript;
|
|
|
+import org.springframework.data.redis.core.types.Expiration;
|
|
|
+import org.springframework.util.StringUtils;
|
|
|
+
|
|
|
+import java.nio.charset.Charset;
|
|
|
+import java.util.*;
|
|
|
+import java.util.concurrent.TimeUnit;
|
|
|
+
|
|
|
+public class RedissonTemplateImpl implements RedissonTemplate {
|
|
|
+ /**默认的数据库索引-0*/
|
|
|
+ private static final Integer DEFAULT_DATABASE_INDEX = 0;
|
|
|
+
|
|
|
+ /**默认的上锁成功标志-1L*/
|
|
|
+ private static final Long RELEASE_SUCCESS = 1L;
|
|
|
+
|
|
|
+ private final int database;
|
|
|
+
|
|
|
+ public RedissonTemplateImpl(Integer database) {
|
|
|
+ this.database = database == null || database < 0 ? DEFAULT_DATABASE_INDEX : database;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Boolean exists(Integer databaseIndex, String key) {
|
|
|
+ Boolean hasKey = RedisBeanContext.getRedisTemplate(databaseIndex).hasKey(key);
|
|
|
+ if (null!=hasKey && hasKey){
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Boolean exists(String key) {
|
|
|
+ return exists(database, key);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Long length(Integer databaseIndex, String key) {
|
|
|
+ return RedisBeanContext.getRedisTemplate(databaseIndex).boundValueOps(key).size();
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Long length(String key) {
|
|
|
+ return length(database, key);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void setObj(String key, Object obj) {
|
|
|
+ setObj(database, key, obj);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void setObj(Integer databaseIndex, String key, Object obj) {
|
|
|
+ RedisBeanContext.getRedisTemplate(databaseIndex).boundValueOps(key).set(JSONObject.toJSONString(obj));
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void set(String key, String value) {
|
|
|
+ set(database, key, value);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void set(Integer databaseIndex, String key, String value) {
|
|
|
+ RedisTemplate<Object, Object> redisTemplate = RedisBeanContext.getRedisTemplate(databaseIndex);
|
|
|
+ redisTemplate.boundValueOps(key).set(value);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void setex(String key, String value, int seconds) {
|
|
|
+ setex(database, key, value, seconds);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void setex(Integer databaseIndex, String key, String value, int seconds) {
|
|
|
+ if (seconds<0){
|
|
|
+ set(databaseIndex, key, value);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ RedisBeanContext.getRedisTemplate(databaseIndex).boundValueOps(key).set(value,seconds, TimeUnit.SECONDS);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void setexObj(Integer databaseIndex, String key, Object obj, int seconds) {
|
|
|
+ if (seconds<0){
|
|
|
+ setObj(databaseIndex, key, obj);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ RedisBeanContext.getRedisTemplate(databaseIndex).boundValueOps(key).set(JSONObject.toJSONString(obj),seconds, TimeUnit.SECONDS);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public String get(String key) {
|
|
|
+ return get(database, key);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public String get(Integer databaseIndex, String key) {
|
|
|
+ RedisTemplate<String, String> redisTemplate = RedisBeanContext.getRedisTemplate(databaseIndex);
|
|
|
+ return redisTemplate.boundValueOps(key).get();
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public List<String> get(String... keys) {
|
|
|
+ return get(database, keys);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public List<String> get(Integer databaseIndex, String... keys) {
|
|
|
+ RedisTemplate<String, String> redisTemplate = RedisBeanContext.getRedisTemplate(databaseIndex);
|
|
|
+ return redisTemplate.opsForValue().multiGet(Arrays.asList(keys));
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Set<String> scan(int databaseIndex, String regx) {
|
|
|
+ RedisTemplate<String, String> redisTemplate = RedisBeanContext.getRedisTemplate(databaseIndex);
|
|
|
+ return redisTemplate.execute((RedisCallback<Set<String>>) connection -> {
|
|
|
+ Set<String> keysTmp = new HashSet<>();
|
|
|
+ Cursor<byte[]> cursor = connection.scan(new ScanOptions.ScanOptionsBuilder().match(regx).count(Long.MAX_VALUE).build());
|
|
|
+ while (cursor.hasNext()) {
|
|
|
+ keysTmp.add(new String(cursor.next()));
|
|
|
+ }
|
|
|
+ return keysTmp;
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Set<String> scan(String regx) {
|
|
|
+ return scan(database, regx);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public <T> T getObj(String key, Class<T> clazz) {
|
|
|
+ return getObj(database, key, clazz);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public <T> T getObj(Integer databaseIndex, String key, Class<T> clazz) {
|
|
|
+ RedisTemplate<String, String> redisTemplate = RedisBeanContext.getRedisTemplate(databaseIndex);
|
|
|
+ BoundValueOperations<String, String> operations = redisTemplate.boundValueOps(key);
|
|
|
+ String objStr = operations.get();
|
|
|
+ if (StringUtils.isEmpty(objStr)){
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ return JSONObject.parseObject(objStr, clazz);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Long getTtl(Integer databaseIndex, String key) {
|
|
|
+ RedisTemplate<String, String> redisTemplate = RedisBeanContext.getRedisTemplate(databaseIndex);
|
|
|
+ return redisTemplate.getExpire(key, TimeUnit.SECONDS);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Long getTtl(String key) {
|
|
|
+ return getTtl(database, key);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void setTtl(Integer databaseIndex, String key, int seconds) {
|
|
|
+ RedisTemplate<String, String> redisTemplate = RedisBeanContext.getRedisTemplate(databaseIndex);
|
|
|
+ redisTemplate.expire(key,seconds, TimeUnit.SECONDS);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void setTtl(String key, int seconds) {
|
|
|
+ setTtl(database, key, seconds);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Boolean removeTtl(Integer databaseIndex, String key) {
|
|
|
+ RedisTemplate<String, String> redisTemplate = RedisBeanContext.getRedisTemplate(databaseIndex);
|
|
|
+ return redisTemplate.expire(key,-1L,TimeUnit.SECONDS);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Boolean removeTtl(String key) {
|
|
|
+ return removeTtl(database,key);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Boolean delete(String key) {
|
|
|
+ return delete(database, key);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Boolean delete(Integer databaseIndex, String key) {
|
|
|
+ RedisTemplate<String, String> redisTemplate = RedisBeanContext.getRedisTemplate(databaseIndex);
|
|
|
+ return redisTemplate.delete(key);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Long incr(Integer databaseIndex, String key) {
|
|
|
+ RedisTemplate<String, String> redisTemplate = RedisBeanContext.getRedisTemplate(databaseIndex);
|
|
|
+ return redisTemplate.opsForValue().increment(key,1);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Long incr(String key) {
|
|
|
+ return incr(database,key);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void hset(Integer databaseIndex, String key, String field, String value) {
|
|
|
+ RedisTemplate<String, String> redisTemplate = RedisBeanContext.getRedisTemplate(databaseIndex);
|
|
|
+ BoundHashOperations<String, String, String> hashOperations = redisTemplate.boundHashOps(key);
|
|
|
+ hashOperations.put(field,value);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void hset(String key, String field, String value) {
|
|
|
+ hset(database, key, field, value);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public String hget(Integer databaseIndex, String key, String field) {
|
|
|
+ RedisTemplate<String, String> redisTemplate = RedisBeanContext.getRedisTemplate(databaseIndex);
|
|
|
+ BoundHashOperations<String, String, String> hashOperations = redisTemplate.boundHashOps(key);
|
|
|
+ return hashOperations.get(field);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public String hget(String key, String field) {
|
|
|
+ return hget(database, key, field);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Long hdel(Integer databaseIndex, String key, String field) {
|
|
|
+ RedisTemplate<String, String> redisTemplate = RedisBeanContext.getRedisTemplate(databaseIndex);
|
|
|
+ BoundHashOperations<String, String, String> hashOperations = redisTemplate.boundHashOps(key);
|
|
|
+ return hashOperations.delete(field);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Long hdel(String key, String field) {
|
|
|
+ return hdel(database, key, field);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void hmset(Integer databaseIndex, String key, Map<String, String> map) {
|
|
|
+ RedisTemplate<String, String> redisTemplate = RedisBeanContext.getRedisTemplate(databaseIndex);
|
|
|
+ BoundHashOperations<String, String, String> hashOperations = redisTemplate.boundHashOps(key);
|
|
|
+ hashOperations.putAll(map);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void hmset(String key, Map<String, String> map) {
|
|
|
+ hmset(database, key, map);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public List<String> hmget(Integer databaseIndex, String key, String... fields) {
|
|
|
+ RedisTemplate<String, String> redisTemplate = RedisBeanContext.getRedisTemplate(databaseIndex);
|
|
|
+ BoundHashOperations<String, String, String> hashOperations = redisTemplate.boundHashOps(key);
|
|
|
+ return hashOperations.multiGet(Arrays.asList(fields));
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public List<String> hmget(String key, String... fields) {
|
|
|
+ return hmget(database, key, fields);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Long hlen(Integer databaseIndex, String key) {
|
|
|
+ RedisTemplate<String, String> redisTemplate = RedisBeanContext.getRedisTemplate(databaseIndex);
|
|
|
+ BoundHashOperations<String, String, String> hashOperations = redisTemplate.boundHashOps(key);
|
|
|
+ return hashOperations.size();
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Long hlen(String key) {
|
|
|
+ return hlen(database, key);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Map<String, String> hgetAll(Integer databaseIndex, String key) {
|
|
|
+ RedisTemplate<String, String> redisTemplate = RedisBeanContext.getRedisTemplate(databaseIndex);
|
|
|
+ BoundHashOperations<String, String, String> hashOperations = redisTemplate.boundHashOps(key);
|
|
|
+ return hashOperations.entries();
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Map<String, String> hgetAll(String key) {
|
|
|
+ return hgetAll(database, key);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void lpush(Integer databaseIndex, String key, String... values) {
|
|
|
+ RedisTemplate<String, String> redisTemplate = RedisBeanContext.getRedisTemplate(databaseIndex);
|
|
|
+ BoundListOperations<String, String> listOperations = redisTemplate.boundListOps(key);
|
|
|
+ listOperations.leftPushAll(values);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void lpush(String key, String... values) {
|
|
|
+ lpush(database, key, values);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void rpush(Integer databaseIndex, String key, String... values) {
|
|
|
+ RedisTemplate<String, String> redisTemplate = RedisBeanContext.getRedisTemplate(databaseIndex);
|
|
|
+ BoundListOperations<String, String> listOperations = redisTemplate.boundListOps(key);
|
|
|
+ listOperations.rightPushAll(values);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void rpush(String key, String... values) {
|
|
|
+ rpush(database, key, values);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Long llen(Integer databaseIndex, String key) {
|
|
|
+ RedisTemplate<String, String> redisTemplate = RedisBeanContext.getRedisTemplate(databaseIndex);
|
|
|
+ BoundListOperations<String, String> listOperations = redisTemplate.boundListOps(key);
|
|
|
+ return listOperations.size();
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Long llen(String key) {
|
|
|
+ return llen(database, key);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public String lindex(Integer databaseIndex, String key, long index) {
|
|
|
+ RedisTemplate<String, String> redisTemplate = RedisBeanContext.getRedisTemplate(databaseIndex);
|
|
|
+ BoundListOperations<String, String> listOperations = redisTemplate.boundListOps(key);
|
|
|
+ return listOperations.index(index);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public String lindex(String key, long index) {
|
|
|
+ return lindex(database, key, index);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public List<String> lrangeAll(Integer databaseIndex, String key) {
|
|
|
+ RedisTemplate<String, String> redisTemplate = RedisBeanContext.getRedisTemplate(databaseIndex);
|
|
|
+ BoundListOperations<String, String> listOperations = redisTemplate.boundListOps(key);
|
|
|
+ return listOperations.range(0, -1);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public List<String> lrangeAll(String key) {
|
|
|
+ return lrangeAll(database, key);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public List<String> lrange(Integer databaseIndex, String key, long start, long end) {
|
|
|
+ RedisTemplate<String, String> redisTemplate = RedisBeanContext.getRedisTemplate(databaseIndex);
|
|
|
+ BoundListOperations<String, String> listOperations = redisTemplate.boundListOps(key);
|
|
|
+ return listOperations.range(start, end);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public List<String> lrange(String key, long start, long end) {
|
|
|
+ return lrange(database, key, start, end);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public String lpop(Integer databaseIndex, String key) {
|
|
|
+ RedisTemplate<String, String> redisTemplate = RedisBeanContext.getRedisTemplate(databaseIndex);
|
|
|
+ BoundListOperations<String, String> listOperations = redisTemplate.boundListOps(key);
|
|
|
+ return listOperations.leftPop();
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public String lpop(String key) {
|
|
|
+ return lpop(database, key);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public String rpop(Integer databaseIndex, String key) {
|
|
|
+ RedisTemplate<String, String> redisTemplate = RedisBeanContext.getRedisTemplate(databaseIndex);
|
|
|
+ BoundListOperations<String, String> listOperations = redisTemplate.boundListOps(key);
|
|
|
+ return listOperations.rightPop();
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public String rpop(String key) {
|
|
|
+ return rpop(database, key);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Boolean tryLock(Integer databaseIndex, String lockKey, String lockValue, long expire) {
|
|
|
+ RedisTemplate<String, String> redisTemplate = RedisBeanContext.getRedisTemplate(databaseIndex);
|
|
|
+ Boolean result = redisTemplate.execute((RedisCallback<Boolean>) connection -> {
|
|
|
+ byte[] key = lockKey.getBytes(Charset.forName("UTF-8"));
|
|
|
+ byte[] value = lockValue.getBytes(Charset.forName("UTF-8"));
|
|
|
+ Expiration expiration = Expiration.seconds(TimeUnit.SECONDS.toSeconds(expire));
|
|
|
+ RedisStringCommands.SetOption option = RedisStringCommands.SetOption.SET_IF_ABSENT;
|
|
|
+ return connection.set(key, value, expiration, option);
|
|
|
+ });
|
|
|
+
|
|
|
+ if (null!=result && result) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Boolean tryLock(String lockKey, String lockValue, long expire) {
|
|
|
+ return tryLock(database, lockKey, lockValue, expire);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Boolean unLock(Integer databaseIndex, String lockKey, String lockValue) {
|
|
|
+ RedisTemplate<String, String> redisTemplate = RedisBeanContext.getRedisTemplate(databaseIndex);
|
|
|
+ if (StringUtils.isEmpty(lockValue)) {
|
|
|
+ String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
|
|
|
+ Object execute = redisTemplate.execute(RedisScript.of(script,Long.class), Collections.singletonList(lockKey), lockValue);
|
|
|
+ if (RELEASE_SUCCESS.equals(execute)) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Boolean unLock(String lockKey, String lockValue) {
|
|
|
+ return unLock(database, lockKey, lockValue);
|
|
|
+ }
|
|
|
+
|
|
|
+ private RLock getLock(String key, boolean isFair) {
|
|
|
+ RedissonClient redisson = RedisBeanContext.getRedissonClient(database);
|
|
|
+ if (isFair) {
|
|
|
+ return redisson.getFairLock(CommonConstant.LOCK_KEY_PREFIX + key);
|
|
|
+ }
|
|
|
+ return redisson.getLock(CommonConstant.LOCK_KEY_PREFIX + key);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public RLock lock(String key, long leaseTime, TimeUnit unit, boolean isFair) {
|
|
|
+ RLock lock = getLock(key, isFair);
|
|
|
+ lock.lock(leaseTime, unit);
|
|
|
+ return lock;
|
|
|
+ }
|
|
|
+ @Override
|
|
|
+ public RLock lock(String key, long leaseTime, TimeUnit unit) {
|
|
|
+ return lock(key, leaseTime, unit, false);
|
|
|
+ }
|
|
|
+ @Override
|
|
|
+ public RLock lock(String key, boolean isFair) {
|
|
|
+ return lock(key, -1, null, isFair);
|
|
|
+ }
|
|
|
+ @Override
|
|
|
+ public RLock lock(String key) {
|
|
|
+ return lock(key, -1, null, false);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public RLock tryLock(String key, long waitTime, long leaseTime, TimeUnit unit, boolean isFair) throws InterruptedException {
|
|
|
+ RLock lock = getLock(key, isFair);
|
|
|
+ if (lock.tryLock(waitTime, leaseTime, unit)) {
|
|
|
+ return lock;
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ @Override
|
|
|
+ public RLock tryLock(String key, long waitTime, long leaseTime, TimeUnit unit) throws InterruptedException {
|
|
|
+ return tryLock(key, waitTime, leaseTime, unit, false);
|
|
|
+ }
|
|
|
+ @Override
|
|
|
+ public RLock tryLock(String key, long waitTime, TimeUnit unit, boolean isFair) throws InterruptedException {
|
|
|
+ return tryLock(key, waitTime, -1, unit, isFair);
|
|
|
+ }
|
|
|
+ @Override
|
|
|
+ public RLock tryLock(String key, long waitTime, TimeUnit unit) throws InterruptedException {
|
|
|
+ return tryLock(key, waitTime, -1, unit, false);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void unlock(Object lock) {
|
|
|
+ if (lock != null) {
|
|
|
+ if (lock instanceof RLock) {
|
|
|
+ RLock rLock = (RLock)lock;
|
|
|
+ if (rLock.isLocked()) {
|
|
|
+ rLock.unlock();
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ throw new LockException("requires RLock type");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|