优化锁逻辑

This commit is contained in:
周浩
2016-05-28 11:42:44 +08:00
parent 8ff57b8469
commit d3b7140265
3 changed files with 95 additions and 50 deletions

View File

@@ -49,12 +49,12 @@ public class AnnotationLockAopAdvice {
}
}
try {
logger.debug("try lock :", name);
logger.debug("try lock :{}", name);
boolean locked = _lock.tryLock(lock.waitTime(), lock.timeUnit());
if (!locked) throw new LockException(name + "error");
return pjp.proceed();
} finally {
logger.debug("unlock :", name);
logger.debug("unlock :{}", name);
unlock(_lock);
}
}

View File

@@ -1,6 +1,5 @@
package org.hsweb.concurrent.lock.support.redis;
import org.hsweb.concurrent.lock.exception.LockException;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.Assert;
@@ -15,8 +14,10 @@ import java.util.concurrent.locks.Lock;
public class RedisLock implements Lock {
static final String PREFIX = "lock:";
static final byte[] LOCK_VALUE = new byte[0];
static final long DEFAULT_EXPIRE = 60;
private long lockKeyExpireTime = DEFAULT_EXPIRE;
private long waitTime = 30;
protected byte[] lockValue;
private RedisTemplate redisTemplate;
private String key;
@@ -29,6 +30,7 @@ public class RedisLock implements Lock {
Assert.notNull(redisTemplate);
this.key = key;
this.redisTemplate = redisTemplate;
lockValue = new byte[0];
}
@Override
@@ -36,8 +38,11 @@ public class RedisLock implements Lock {
redisTemplate.execute((RedisCallback<Boolean>) connection -> {
boolean locked = false;
do {
locked = connection.setNX(getKey(), LOCK_VALUE);
sleep();
locked = connection.setNX(getKey(), lockValue);
if (locked) {
connection.expire(getKey(), lockKeyExpireTime);
} else
sleep();
} while (!locked);
return true;
});
@@ -45,17 +50,22 @@ public class RedisLock implements Lock {
@Override
public void lockInterruptibly() throws InterruptedException {
boolean locked = (Boolean) redisTemplate.execute((RedisCallback<Boolean>) connection ->
connection.setNX(getKey(), LOCK_VALUE)
);
boolean locked = (Boolean) redisTemplate.execute((RedisCallback<Boolean>) connection -> {
boolean l = connection.setNX(getKey(), lockValue);
if (l) connection.expire(getKey(), lockKeyExpireTime);
return l;
});
if (!locked) throw new InterruptedException(new String(getKey()) + " is locked!");
}
@Override
public boolean tryLock() {
return (Boolean) redisTemplate.execute((RedisCallback<Boolean>) connection ->
connection.setNX(getKey(), LOCK_VALUE)
);
try {
lockInterruptibly();
return true;
} catch (InterruptedException e) {
return false;
}
}
@Override
@@ -65,9 +75,9 @@ public class RedisLock implements Lock {
boolean locked = false;
long startWith = System.nanoTime();
do {
locked = connection.setNX(getKey(), LOCK_VALUE);
locked = connection.setNX(getKey(), lockValue);
if (locked) {
connection.expire(getKey(), 30);
connection.expire(getKey(), lockKeyExpireTime);
return true;
}
long now = System.nanoTime();
@@ -92,12 +102,12 @@ public class RedisLock implements Lock {
@Override
public Condition newCondition() {
throw new LockException("method not support");
throw new UnsupportedOperationException();
}
protected void sleep() {
try {
Thread.sleep(10);
Thread.sleep(waitTime);
} catch (InterruptedException e) {
}
}

View File

@@ -4,6 +4,7 @@ import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.Assert;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
@@ -14,13 +15,14 @@ import java.util.concurrent.locks.ReadWriteLock;
*/
public class RedisReadWriteLock implements ReadWriteLock {
static final String PREFIX = "lock:";
static final byte[] LOCK_VALUE = new byte[0];
static final long DEFAULT_EXPIRE = 60;
private ReadLock readLock;
private WriteLock writeLock;
private String key;
private long lockKeyExpireTime = DEFAULT_EXPIRE;
private long waitTime = 30;
protected byte[] lockValue;
private byte[] readLockKey, writeLockKey;
private RedisTemplate redisTemplate;
@@ -31,6 +33,9 @@ public class RedisReadWriteLock implements ReadWriteLock {
this.redisTemplate = redisTemplate;
readLock = new ReadLock();
writeLock = new WriteLock();
readLockKey = (PREFIX + key + ".read.lock").getBytes();
writeLockKey = (PREFIX + key + ".write.lock").getBytes();
lockValue = (UUID.randomUUID().toString()).getBytes();
}
@Override
@@ -44,32 +49,44 @@ public class RedisReadWriteLock implements ReadWriteLock {
}
private byte[] getReadKey() {
return (PREFIX + key + ".read.lock").getBytes();
return readLockKey;
}
private byte[] getWriteKey() {
return (PREFIX + key + ".write.lock").getBytes();
return writeLockKey;
}
protected void sleep() {
try {
Thread.sleep(10);
Thread.sleep(waitTime);
} catch (InterruptedException e) {
}
}
public void setWaitTime(long waitTime) {
this.waitTime = waitTime;
}
public void setLockKeyExpireTime(long lockKeyExpireTime) {
this.lockKeyExpireTime = lockKeyExpireTime;
}
class ReadLock implements Lock {
public byte[] lockValue() {
return new String(lockValue).concat(Thread.currentThread().getId() + "").getBytes();
}
@Override
public void lock() {
redisTemplate.execute((RedisCallback<String>) connection -> {
boolean locked = false;
do {
locked = connection.exists(getWriteKey());
if (!locked) {
connection.setNX(getReadKey(), LOCK_VALUE);
if (!connection.exists(getWriteKey())) {
connection.setNX(getReadKey(), lockValue());
connection.expire(getReadKey(), lockKeyExpireTime);
locked = true;
}
sleep();
} else
sleep();
} while (!locked);
return null;
});
@@ -81,7 +98,9 @@ public class RedisReadWriteLock implements ReadWriteLock {
{
boolean writeLocked = connection.exists(getWriteKey());
if (!writeLocked) {
connection.setNX(getReadKey(), LOCK_VALUE);
if (connection.setNX(getReadKey(), lockValue)) {
connection.expire(getReadKey(), lockKeyExpireTime);
}
writeLocked = true;
}
return writeLocked;
@@ -92,8 +111,12 @@ public class RedisReadWriteLock implements ReadWriteLock {
@Override
public boolean tryLock() {
return (Boolean) redisTemplate.execute((RedisCallback<Boolean>) connection ->
connection.setNX(getReadKey(), LOCK_VALUE)
);
{
if (connection.setNX(getReadKey(), lockValue)) {
connection.expire(getReadKey(), lockKeyExpireTime);
}
return false;
});
}
@Override
@@ -103,10 +126,9 @@ public class RedisReadWriteLock implements ReadWriteLock {
boolean locked = false;
long startWith = System.nanoTime();
do {
locked = connection.exists(getWriteKey());
if (!locked) {
connection.setNX(getReadKey(), LOCK_VALUE);
connection.expire(getReadKey(), 30);
if (!connection.exists(getWriteKey())) {
connection.setNX(getReadKey(), lockValue);
connection.expire(getReadKey(), lockKeyExpireTime);
return true;
}
long now = System.nanoTime();
@@ -116,22 +138,30 @@ public class RedisReadWriteLock implements ReadWriteLock {
}
sleep();
} while (!locked);
return null;
return false;
});
if (error[0] == 1) {
throw new InterruptedException("lock time out!");
throw new InterruptedException("try lock time out!");
}
return success;
}
@Override
public void unlock() {
redisTemplate.execute((RedisCallback) conn -> conn.del(getReadKey()));
redisTemplate.execute((RedisCallback) conn -> {
byte[] lock = conn.get(getReadKey());
if (lock == null) return null;
//当前读锁为自己持有 才解锁
if (new String(lock).equals(new String(lockValue()))) {
conn.del(getReadKey());
}
return null;
});
}
@Override
public Condition newCondition() {
return null;
throw new UnsupportedOperationException();
}
}
@@ -143,9 +173,10 @@ public class RedisReadWriteLock implements ReadWriteLock {
do {
readLocked = connection.exists(getReadKey());
if (!readLocked) {
locked = connection.setNX(getWriteKey(), LOCK_VALUE);
}
sleep();
locked = connection.setNX(getWriteKey(), lockValue);
connection.expire(getWriteKey(), lockKeyExpireTime);
} else
sleep();
} while (!locked);
return null;
});
@@ -157,7 +188,9 @@ public class RedisReadWriteLock implements ReadWriteLock {
{
boolean readLocked = connection.exists(getReadKey());
if (!readLocked) {
return connection.setNX(getWriteKey(), LOCK_VALUE);
boolean _locked = connection.setNX(getWriteKey(), lockValue);
if (_locked) connection.expire(getWriteKey(), lockKeyExpireTime);
return _locked;
}
return false;
});
@@ -168,7 +201,10 @@ public class RedisReadWriteLock implements ReadWriteLock {
public boolean tryLock() {
return (Boolean) redisTemplate.execute((RedisCallback<Boolean>) connection -> {
if (connection.exists(getReadKey())) return false;
return connection.setNX(getWriteKey(), LOCK_VALUE);
boolean locked = connection.setNX(getWriteKey(), lockValue);
if (locked)
connection.expire(getWriteKey(), lockKeyExpireTime);
return locked;
});
}
@@ -179,11 +215,10 @@ public class RedisReadWriteLock implements ReadWriteLock {
boolean locked = false;
long startWith = System.nanoTime();
do {
locked = connection.exists(getReadKey());
if (!locked) {
locked = connection.setNX(getWriteKey(), LOCK_VALUE);
if (!connection.exists(getReadKey())) {
locked = connection.setNX(getWriteKey(), lockValue);
if (locked) {
connection.expire(getWriteKey(), 30);
connection.expire(getWriteKey(), lockKeyExpireTime);
return true;
}
}
@@ -209,7 +244,7 @@ public class RedisReadWriteLock implements ReadWriteLock {
@Override
public Condition newCondition() {
return null;
throw new UnsupportedOperationException();
}
}
}