From 67f8b1e2a772fc4d400fea6457e62dfcba8e6f3d Mon Sep 17 00:00:00 2001 From: "binbin.hou" Date: Mon, 19 Oct 2020 18:23:20 +0800 Subject: [PATCH] [Feature] add for new --- .../houbb/lock/api/core/IReadWriteLock.java | 11 +++ ...stractLockRedis.java => AbstractLock.java} | 13 ++-- .../houbb/lock/redis/core/LockRedis.java | 2 +- .../houbb/lock/redis/core/LockSpin.java | 44 ++++++++++++ .../houbb/lock/redis/core/LockSpinRe.java | 70 +++++++++++++++++++ .../houbb/lock/redis/core/LockWaitNotify.java | 52 ++++++++++++++ .../redis/exception/LockRuntimeException.java | 27 +++++++ .../lock/test/core/LockSpinReThread.java | 36 ++++++++++ .../houbb/lock/test/core/LockSpinThread.java | 35 ++++++++++ .../lock/test/core/LockWaitNotifyThread.java | 43 ++++++++++++ ...{RedisLockTest.java => LockRedisTest.java} | 2 +- 11 files changed, 329 insertions(+), 6 deletions(-) create mode 100644 lock-api/src/main/java/com/github/houbb/lock/api/core/IReadWriteLock.java rename lock-core/src/main/java/com/github/houbb/lock/redis/core/{AbstractLockRedis.java => AbstractLock.java} (86%) create mode 100644 lock-core/src/main/java/com/github/houbb/lock/redis/core/LockSpin.java create mode 100644 lock-core/src/main/java/com/github/houbb/lock/redis/core/LockSpinRe.java create mode 100644 lock-core/src/main/java/com/github/houbb/lock/redis/core/LockWaitNotify.java create mode 100644 lock-core/src/main/java/com/github/houbb/lock/redis/exception/LockRuntimeException.java create mode 100644 lock-test/src/main/java/com/github/houbb/lock/test/core/LockSpinReThread.java create mode 100644 lock-test/src/main/java/com/github/houbb/lock/test/core/LockSpinThread.java create mode 100644 lock-test/src/main/java/com/github/houbb/lock/test/core/LockWaitNotifyThread.java rename lock-test/src/test/java/com/github/houbb/lock/test/{RedisLockTest.java => LockRedisTest.java} (96%) diff --git a/lock-api/src/main/java/com/github/houbb/lock/api/core/IReadWriteLock.java b/lock-api/src/main/java/com/github/houbb/lock/api/core/IReadWriteLock.java new file mode 100644 index 0000000..eb56167 --- /dev/null +++ b/lock-api/src/main/java/com/github/houbb/lock/api/core/IReadWriteLock.java @@ -0,0 +1,11 @@ +package com.github.houbb.lock.api.core; + +import java.util.concurrent.locks.ReadWriteLock; + +/** + * 读写锁定义 + * @author binbin.hou + * @since 0.0.2 + */ +public interface IReadWriteLock extends ReadWriteLock { +} diff --git a/lock-core/src/main/java/com/github/houbb/lock/redis/core/AbstractLockRedis.java b/lock-core/src/main/java/com/github/houbb/lock/redis/core/AbstractLock.java similarity index 86% rename from lock-core/src/main/java/com/github/houbb/lock/redis/core/AbstractLockRedis.java rename to lock-core/src/main/java/com/github/houbb/lock/redis/core/AbstractLock.java index e6c64ee..d2d6b34 100644 --- a/lock-core/src/main/java/com/github/houbb/lock/redis/core/AbstractLockRedis.java +++ b/lock-core/src/main/java/com/github/houbb/lock/redis/core/AbstractLock.java @@ -3,6 +3,7 @@ package com.github.houbb.lock.redis.core; import com.github.houbb.lock.api.core.ILock; import com.github.houbb.lock.redis.constant.LockRedisConst; import com.github.houbb.wait.api.IWait; +import com.github.houbb.wait.core.Waits; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Condition; @@ -12,7 +13,7 @@ import java.util.concurrent.locks.Condition; * @author binbin.hou * @since 0.0.1 */ -public abstract class AbstractLockRedis implements ILock { +public abstract class AbstractLock implements ILock { /** * 锁等待 @@ -20,7 +21,11 @@ public abstract class AbstractLockRedis implements ILock { */ private final IWait wait; - protected AbstractLockRedis(IWait wait) { + public AbstractLock() { + this.wait = Waits.threadSleep(); + } + + protected AbstractLock(IWait wait) { this.wait = wait; } @@ -68,8 +73,8 @@ public abstract class AbstractLockRedis implements ILock { return true; } - // 等待 10ms - wait.wait(TimeUnit.MILLISECONDS, 10); + // 等待 1ms + wait.wait(TimeUnit.MILLISECONDS, 1); } return false; } diff --git a/lock-core/src/main/java/com/github/houbb/lock/redis/core/LockRedis.java b/lock-core/src/main/java/com/github/houbb/lock/redis/core/LockRedis.java index af2e129..b744538 100644 --- a/lock-core/src/main/java/com/github/houbb/lock/redis/core/LockRedis.java +++ b/lock-core/src/main/java/com/github/houbb/lock/redis/core/LockRedis.java @@ -16,7 +16,7 @@ import com.github.houbb.wait.api.IWait; * @author binbin.hou * @since 0.0.1 */ -public class LockRedis extends AbstractLockRedis { +public class LockRedis extends AbstractLock { /** * redis 操作实现 diff --git a/lock-core/src/main/java/com/github/houbb/lock/redis/core/LockSpin.java b/lock-core/src/main/java/com/github/houbb/lock/redis/core/LockSpin.java new file mode 100644 index 0000000..2d2f3e8 --- /dev/null +++ b/lock-core/src/main/java/com/github/houbb/lock/redis/core/LockSpin.java @@ -0,0 +1,44 @@ +package com.github.houbb.lock.redis.core; + +import com.github.houbb.lock.redis.exception.LockRuntimeException; + +import java.util.concurrent.atomic.AtomicReference; + +/** + * 自旋锁 + * @author binbin.hou + * @since 0.0.2 + */ +public class LockSpin extends AbstractLock { + + /** + * volatile 引用,保证线程间的可见性+易变性 + * + * @since 0.0.2 + */ + private AtomicReference owner =new AtomicReference<>(); + + @Override + public void lock() { + // 循环等待,直到获取到锁 + while (!tryLock()) { + } + } + + @Override + public boolean tryLock(String key) { + Thread current = Thread.currentThread(); + // CAS + return owner.compareAndSet(null, current); + } + + @Override + public void unlock(String key) { + Thread current = Thread.currentThread(); + boolean result = owner.compareAndSet(current, null); + if(!result) { + throw new LockRuntimeException("解锁失败"); + } + } + +} diff --git a/lock-core/src/main/java/com/github/houbb/lock/redis/core/LockSpinRe.java b/lock-core/src/main/java/com/github/houbb/lock/redis/core/LockSpinRe.java new file mode 100644 index 0000000..8dd908b --- /dev/null +++ b/lock-core/src/main/java/com/github/houbb/lock/redis/core/LockSpinRe.java @@ -0,0 +1,70 @@ +package com.github.houbb.lock.redis.core; + +import com.github.houbb.heaven.util.util.DateUtil; +import com.github.houbb.lock.redis.exception.LockRuntimeException; + +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.atomic.AtomicReference; + +/** + * 自旋锁-可重入 + * @author binbin.hou + * @since 0.0.2 + */ +public class LockSpinRe extends AbstractLock { + + /** + * volatile 引用,保证线程间的可见性+易变性 + * + * @since 0.0.2 + */ + private AtomicReference owner =new AtomicReference<>(); + + /** + * 计数统计类 + * + * @since 0.0.2 + */ + private AtomicLong count = new AtomicLong(0); + + @Override + public void lock() { + // 循环等待,直到获取到锁 + while (!tryLock()) { + // sleep + DateUtil.sleep(1); + } + } + + @Override + public boolean tryLock(String key) { + Thread current = Thread.currentThread(); + // 判断是否已经拥有此锁 + if(current == owner.get()) { + // 原子性自增 1 + count.incrementAndGet(); + + return true; + } + + // CAS + return owner.compareAndSet(null, current); + } + + @Override + public void unlock(String key) { + Thread current = Thread.currentThread(); + + // 可重入实现 + if(owner.get() == current && count.get() != 0) { + count.decrementAndGet(); + return; + } + + boolean result = owner.compareAndSet(current, null); + if(!result) { + throw new LockRuntimeException("解锁失败"); + } + } + +} diff --git a/lock-core/src/main/java/com/github/houbb/lock/redis/core/LockWaitNotify.java b/lock-core/src/main/java/com/github/houbb/lock/redis/core/LockWaitNotify.java new file mode 100644 index 0000000..739698a --- /dev/null +++ b/lock-core/src/main/java/com/github/houbb/lock/redis/core/LockWaitNotify.java @@ -0,0 +1,52 @@ +package com.github.houbb.lock.redis.core; + +import com.github.houbb.lock.redis.exception.LockRuntimeException; + +import java.util.concurrent.atomic.AtomicReference; + +/** + * 等待通知的锁实现 + * @author binbin.hou + * @since 0.0.2 + */ +public class LockWaitNotify extends AbstractLock { + + /** + * volatile 引用,保证线程间的可见性+易变性 + * + * @since 0.0.2 + */ + private AtomicReference owner =new AtomicReference<>(); + + @Override + public synchronized void lock() { + while (!tryLock()) { + try { + wait(); + } catch (InterruptedException e) { + e.printStackTrace(); + // 是否可以被打断 + } + } + } + + @Override + public boolean tryLock(String key) { + Thread current = Thread.currentThread(); + // CAS + return owner.compareAndSet(null, current); + } + + @Override + public synchronized void unlock(String key) { + Thread current = Thread.currentThread(); + boolean result = owner.compareAndSet(current, null); + if(!result) { + throw new LockRuntimeException("解锁失败"); + } + + // 唤醒等待中的线程 + notifyAll(); + } + +} diff --git a/lock-core/src/main/java/com/github/houbb/lock/redis/exception/LockRuntimeException.java b/lock-core/src/main/java/com/github/houbb/lock/redis/exception/LockRuntimeException.java new file mode 100644 index 0000000..68e485f --- /dev/null +++ b/lock-core/src/main/java/com/github/houbb/lock/redis/exception/LockRuntimeException.java @@ -0,0 +1,27 @@ +package com.github.houbb.lock.redis.exception; + +/** + * @author binbin.hou + * @since 0.0.2 + */ +public class LockRuntimeException extends RuntimeException { + + public LockRuntimeException() { + } + + public LockRuntimeException(String message) { + super(message); + } + + public LockRuntimeException(String message, Throwable cause) { + super(message, cause); + } + + public LockRuntimeException(Throwable cause) { + super(cause); + } + + public LockRuntimeException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } +} diff --git a/lock-test/src/main/java/com/github/houbb/lock/test/core/LockSpinReThread.java b/lock-test/src/main/java/com/github/houbb/lock/test/core/LockSpinReThread.java new file mode 100644 index 0000000..c40f7ab --- /dev/null +++ b/lock-test/src/main/java/com/github/houbb/lock/test/core/LockSpinReThread.java @@ -0,0 +1,36 @@ +package com.github.houbb.lock.test.core; + +import com.github.houbb.lock.api.core.ILock; +import com.github.houbb.lock.redis.core.LockSpin; +import com.github.houbb.lock.redis.core.LockSpinRe; + +/** + * @author binbin.hou + * @since 1.0.0 + */ +public class LockSpinReThread implements Runnable { + + private final ILock lock = new LockSpinRe(); + + @Override + public void run() { + System.out.println("first-lock: " + Thread.currentThread().getId()); + lock.lock(); + + System.out.println("second-lock: " + Thread.currentThread().getId()); + lock.lock(); + lock.unlock(); + System.out.println("second-unlock: " + Thread.currentThread().getId()); + + lock.unlock(); + System.out.println("first-unlock: " + Thread.currentThread().getId()); + } + + public static void main(String[] args) { + final Runnable runnable = new LockSpinReThread(); + new Thread(runnable).start(); + new Thread(runnable).start(); + new Thread(runnable).start(); + } + +} diff --git a/lock-test/src/main/java/com/github/houbb/lock/test/core/LockSpinThread.java b/lock-test/src/main/java/com/github/houbb/lock/test/core/LockSpinThread.java new file mode 100644 index 0000000..0e65dd3 --- /dev/null +++ b/lock-test/src/main/java/com/github/houbb/lock/test/core/LockSpinThread.java @@ -0,0 +1,35 @@ +package com.github.houbb.lock.test.core; + +import com.github.houbb.lock.api.core.ILock; +import com.github.houbb.lock.redis.core.LockSpin; + +/** + * @author binbin.hou + * @since 1.0.0 + */ +public class LockSpinThread implements Runnable { + + private final ILock lock = new LockSpin(); + + @Override + public void run() { + System.out.println("first-lock: " + Thread.currentThread().getId()); + lock.lock(); + + System.out.println("second-lock: " + Thread.currentThread().getId()); + lock.lock(); + lock.unlock(); + System.out.println("second-unlock: " + Thread.currentThread().getId()); + + lock.unlock(); + System.out.println("first-unlock: " + Thread.currentThread().getId()); + } + + public static void main(String[] args) { + final Runnable runnable = new LockSpinThread(); + new Thread(runnable).start(); + new Thread(runnable).start(); + new Thread(runnable).start(); + } + +} diff --git a/lock-test/src/main/java/com/github/houbb/lock/test/core/LockWaitNotifyThread.java b/lock-test/src/main/java/com/github/houbb/lock/test/core/LockWaitNotifyThread.java new file mode 100644 index 0000000..f2da746 --- /dev/null +++ b/lock-test/src/main/java/com/github/houbb/lock/test/core/LockWaitNotifyThread.java @@ -0,0 +1,43 @@ +package com.github.houbb.lock.test.core; + +import com.github.houbb.lock.api.core.ILock; +import com.github.houbb.lock.redis.core.LockWaitNotify; + +import java.util.concurrent.TimeUnit; + +/** + * @author binbin.hou + * @since 1.0.0 + */ +public class LockWaitNotifyThread implements Runnable { + + private final ILock lock = new LockWaitNotify(); + + @Override + public void run() { + System.out.println("first-lock: " + Thread.currentThread().getId()); + lock.lock(); + +// System.out.println("second-lock: " + Thread.currentThread().getId()); +// lock.lock(); +// lock.unlock(); +// System.out.println("second-unlock: " + Thread.currentThread().getId()); + + + try { + TimeUnit.SECONDS.sleep(5); + } catch (InterruptedException e) { + e.printStackTrace(); + } + lock.unlock(); + System.out.println("first-unlock: " + Thread.currentThread().getId()); + } + + public static void main(String[] args) { + final Runnable runnable = new LockWaitNotifyThread(); + new Thread(runnable).start(); + new Thread(runnable).start(); + new Thread(runnable).start(); + } + +} diff --git a/lock-test/src/test/java/com/github/houbb/lock/test/RedisLockTest.java b/lock-test/src/test/java/com/github/houbb/lock/test/LockRedisTest.java similarity index 96% rename from lock-test/src/test/java/com/github/houbb/lock/test/RedisLockTest.java rename to lock-test/src/test/java/com/github/houbb/lock/test/LockRedisTest.java index 5509ccd..8922704 100644 --- a/lock-test/src/test/java/com/github/houbb/lock/test/RedisLockTest.java +++ b/lock-test/src/test/java/com/github/houbb/lock/test/LockRedisTest.java @@ -11,7 +11,7 @@ import redis.clients.jedis.Jedis; * @author binbin.hou * @since 0.0.1 */ -public class RedisLockTest { +public class LockRedisTest { @Test public void helloTest() {