mirror of
https://github.com/hs-web/hsweb-framework.git
synced 2026-06-09 17:34:50 +08:00
优化锁逻辑
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user