From d3b714026586687eeea2d5191abf99271fc12c71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=91=A8=E6=B5=A9?= Date: Sat, 28 May 2016 11:42:44 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E9=94=81=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../lock/support/AnnotationLockAopAdvice.java | 4 +- .../lock/support/redis/RedisLock.java | 40 ++++--- .../support/redis/RedisReadWriteLock.java | 101 ++++++++++++------ 3 files changed, 95 insertions(+), 50 deletions(-) diff --git a/hsweb-web-concurrent/hsweb-web-concurrent-lock/src/main/java/org/hsweb/concurrent/lock/support/AnnotationLockAopAdvice.java b/hsweb-web-concurrent/hsweb-web-concurrent-lock/src/main/java/org/hsweb/concurrent/lock/support/AnnotationLockAopAdvice.java index d04724281..864cee516 100644 --- a/hsweb-web-concurrent/hsweb-web-concurrent-lock/src/main/java/org/hsweb/concurrent/lock/support/AnnotationLockAopAdvice.java +++ b/hsweb-web-concurrent/hsweb-web-concurrent-lock/src/main/java/org/hsweb/concurrent/lock/support/AnnotationLockAopAdvice.java @@ -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); } } diff --git a/hsweb-web-concurrent/hsweb-web-concurrent-lock/src/main/java/org/hsweb/concurrent/lock/support/redis/RedisLock.java b/hsweb-web-concurrent/hsweb-web-concurrent-lock/src/main/java/org/hsweb/concurrent/lock/support/redis/RedisLock.java index d6cc31358..661e121f9 100644 --- a/hsweb-web-concurrent/hsweb-web-concurrent-lock/src/main/java/org/hsweb/concurrent/lock/support/redis/RedisLock.java +++ b/hsweb-web-concurrent/hsweb-web-concurrent-lock/src/main/java/org/hsweb/concurrent/lock/support/redis/RedisLock.java @@ -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) 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) connection -> - connection.setNX(getKey(), LOCK_VALUE) - ); + boolean locked = (Boolean) redisTemplate.execute((RedisCallback) 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) 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) { } } diff --git a/hsweb-web-concurrent/hsweb-web-concurrent-lock/src/main/java/org/hsweb/concurrent/lock/support/redis/RedisReadWriteLock.java b/hsweb-web-concurrent/hsweb-web-concurrent-lock/src/main/java/org/hsweb/concurrent/lock/support/redis/RedisReadWriteLock.java index e466ca30e..b88a8e977 100644 --- a/hsweb-web-concurrent/hsweb-web-concurrent-lock/src/main/java/org/hsweb/concurrent/lock/support/redis/RedisReadWriteLock.java +++ b/hsweb-web-concurrent/hsweb-web-concurrent-lock/src/main/java/org/hsweb/concurrent/lock/support/redis/RedisReadWriteLock.java @@ -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) 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) 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) 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(); } } }