From 56e25d67e3c9660f639b1e9e58df3a48bd7b81c6 Mon Sep 17 00:00:00 2001
From: houbb <1060732496@qq.com>
Date: Mon, 19 Oct 2020 23:38:19 +0800
Subject: [PATCH] [Feature] add for new
---
lock-core/pom.xml | 4 +
.../houbb/lock/redis/core/LockReadWrite.java | 111 +++++++++++
.../lock/redis/core/LockReadWriteOwner.java | 146 ++++++++++++++
.../lock/redis/core/LockReadWriteRe.java | 182 ++++++++++++++++++
.../houbb/lock/redis/core/LockWaitNotify.java | 12 +-
.../lock/redis/core/LockWaitNotifyRe.java | 88 +++++++++
.../lock/test/core/LockWaitNotifyThread.java | 24 +--
.../lock/test/core/LockWaitNotifyThread2.java | 45 +++++
.../test/core/LockWaitNotifyThreadRe.java | 43 +++++
pom.xml | 6 +
10 files changed, 645 insertions(+), 16 deletions(-)
create mode 100644 lock-core/src/main/java/com/github/houbb/lock/redis/core/LockReadWrite.java
create mode 100644 lock-core/src/main/java/com/github/houbb/lock/redis/core/LockReadWriteOwner.java
create mode 100644 lock-core/src/main/java/com/github/houbb/lock/redis/core/LockReadWriteRe.java
create mode 100644 lock-core/src/main/java/com/github/houbb/lock/redis/core/LockWaitNotifyRe.java
create mode 100644 lock-test/src/main/java/com/github/houbb/lock/test/core/LockWaitNotifyThread2.java
create mode 100644 lock-test/src/main/java/com/github/houbb/lock/test/core/LockWaitNotifyThreadRe.java
diff --git a/lock-core/pom.xml b/lock-core/pom.xml
index 892390d..dd1348a 100644
--- a/lock-core/pom.xml
+++ b/lock-core/pom.xml
@@ -32,6 +32,10 @@
com.github.houbb
heaven
+
+ com.github.houbb
+ log-integration
+
diff --git a/lock-core/src/main/java/com/github/houbb/lock/redis/core/LockReadWrite.java b/lock-core/src/main/java/com/github/houbb/lock/redis/core/LockReadWrite.java
new file mode 100644
index 0000000..b913dfc
--- /dev/null
+++ b/lock-core/src/main/java/com/github/houbb/lock/redis/core/LockReadWrite.java
@@ -0,0 +1,111 @@
+package com.github.houbb.lock.redis.core;
+
+import com.github.houbb.log.integration.core.Log;
+import com.github.houbb.log.integration.core.LogFactory;
+
+/**
+ * 读写锁实现
+ *
+ * @author binbin.hou
+ * @since 0.0.2
+ */
+public class LockReadWrite {
+
+ private static final Log log = LogFactory.getLog(LockReadWrite.class);
+
+ /**
+ * 读次数统计
+ */
+ private int readCount = 0;
+
+ /**
+ * 写次数统计
+ */
+ private int writeCount = 0;
+
+ /**
+ * 获取读锁,读锁在写锁不存在的时候才能获取
+ *
+ * @since 0.0.2
+ */
+ public synchronized void lockRead() throws InterruptedException {
+ // 写锁存在,需要wait
+ while (!tryLockRead()) {
+ wait();
+ }
+
+ readCount++;
+ }
+
+ /**
+ * 尝试获取读锁
+ *
+ * @return 是否成功
+ * @since 0.0.2
+ */
+ private boolean tryLockRead() {
+ if (writeCount > 0) {
+ log.debug("当前有写锁,获取读锁失败");
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * 释放读锁
+ *
+ * @since 0.0.2
+ */
+ public synchronized void unlockRead() {
+ readCount--;
+ notifyAll();
+ }
+
+ /**
+ * 获取写锁
+ *
+ * @since 0.0.2
+ */
+ public synchronized void lockWrite() throws InterruptedException {
+ // 写锁存在,需要wait
+ while (!tryLockWrite()) {
+ wait();
+ }
+
+ // 此时已经不存在获取写锁的线程了,因此占坑,防止写锁饥饿
+ writeCount++;
+ }
+
+ /**
+ * 尝试获取写锁
+ *
+ * @return 是否成功
+ * @since 0.0.2
+ */
+ private boolean tryLockWrite() {
+ if (writeCount > 0) {
+ log.debug("当前有其他写锁,获取写锁失败");
+ return false;
+ }
+
+ // 读锁
+ if (readCount > 0) {
+ log.debug("当前有其他读锁,获取写锁失败。");
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * 释放写锁
+ *
+ * @since 0.0.2
+ */
+ public synchronized void unlockWrite() {
+ writeCount--;
+ notifyAll();
+ }
+
+}
diff --git a/lock-core/src/main/java/com/github/houbb/lock/redis/core/LockReadWriteOwner.java b/lock-core/src/main/java/com/github/houbb/lock/redis/core/LockReadWriteOwner.java
new file mode 100644
index 0000000..f3b4980
--- /dev/null
+++ b/lock-core/src/main/java/com/github/houbb/lock/redis/core/LockReadWriteOwner.java
@@ -0,0 +1,146 @@
+package com.github.houbb.lock.redis.core;
+
+import com.github.houbb.log.integration.core.Log;
+import com.github.houbb.log.integration.core.LogFactory;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicReference;
+
+/**
+ * 读写锁实现-保证释放锁时为锁的持有者
+ *
+ * @author binbin.hou
+ * @since 0.0.2
+ */
+public class LockReadWriteOwner {
+
+ private static final Log log = LogFactory.getLog(LockReadWriteOwner.class);
+
+ /**
+ * 如果使用类似 write 的方式,会导致读锁只能有一个。
+ * 调整为使用 HashMap 存放读的信息
+ *
+ * @since 0.0.2
+ */
+ private final Map readCountMap = new HashMap<>();
+
+ /**
+ * volatile 引用,保证线程间的可见性+易变性
+ *
+ * @since 0.0.2
+ */
+ private final AtomicReference writeOwner = new AtomicReference<>();
+
+ /**
+ * 写次数统计
+ */
+ private int writeCount = 0;
+
+ /**
+ * 获取读锁,读锁在写锁不存在的时候才能获取
+ *
+ * @since 0.0.2
+ */
+ public synchronized void lockRead() throws InterruptedException {
+ // 写锁存在,需要wait
+ while (!tryLockRead()) {
+ log.debug("获取读锁失败,进入等待状态。");
+ wait();
+ }
+ }
+
+ /**
+ * 尝试获取读锁
+ *
+ * 读锁之间是不互斥的,这里后续需要优化。
+ *
+ * @return 是否成功
+ * @since 0.0.2
+ */
+ private boolean tryLockRead() {
+ if (writeCount > 0) {
+ log.debug("当前有写锁,获取读锁失败");
+ return false;
+ }
+
+ Thread currentThread = Thread.currentThread();
+ // 次数暂时固定为1,后面如果实现可重入,这里可以改进。
+ this.readCountMap.put(currentThread, 1);
+ return true;
+ }
+
+ /**
+ * 释放读锁
+ *
+ * @since 0.0.2
+ */
+ public synchronized void unlockRead() {
+ Thread currentThread = Thread.currentThread();
+ Integer readCount = readCountMap.get(currentThread);
+
+ if (readCount == null) {
+ throw new RuntimeException("当前线程未持有任何读锁,释放锁失败!");
+ } else {
+ log.debug("释放读锁,唤醒所有等待线程。");
+ notifyAll();
+ }
+ }
+
+ /**
+ * 获取写锁
+ *
+ * @since 0.0.2
+ */
+ public synchronized void lockWrite() throws InterruptedException {
+ // 写锁存在,需要wait
+ while (!tryLockWrite()) {
+ wait();
+ }
+
+ // 此时已经不存在获取写锁的线程了,因此占坑,防止写锁饥饿
+ writeCount++;
+ }
+
+ /**
+ * 尝试获取写锁
+ *
+ * @return 是否成功
+ * @since 0.0.2
+ */
+ private boolean tryLockWrite() {
+ if (writeCount > 0) {
+ log.debug("当前有其他写锁,获取写锁失败");
+ return false;
+ }
+
+ // 读锁
+ if (!readCountMap.isEmpty()) {
+ log.debug("当前有其他读锁,获取写锁失败。");
+ return false;
+ }
+
+ Thread currentThread = Thread.currentThread();
+ boolean result = writeOwner.compareAndSet(null, currentThread);
+ log.debug("尝试获取写锁结果:{}", result);
+ return result;
+ }
+
+ /**
+ * 释放写锁
+ *
+ * @since 0.0.2
+ */
+ public synchronized void unlockWrite() {
+ boolean toNullResult = writeOwner.compareAndSet(Thread.currentThread(), null);
+
+ if (toNullResult) {
+ writeCount--;
+ log.debug("写锁释放,唤醒所有等待线程。");
+ notifyAll();
+ } else {
+ throw new RuntimeException("释放写锁失败");
+ }
+ }
+
+}
diff --git a/lock-core/src/main/java/com/github/houbb/lock/redis/core/LockReadWriteRe.java b/lock-core/src/main/java/com/github/houbb/lock/redis/core/LockReadWriteRe.java
new file mode 100644
index 0000000..1ce5217
--- /dev/null
+++ b/lock-core/src/main/java/com/github/houbb/lock/redis/core/LockReadWriteRe.java
@@ -0,0 +1,182 @@
+package com.github.houbb.lock.redis.core;
+
+import com.github.houbb.log.integration.core.Log;
+import com.github.houbb.log.integration.core.LogFactory;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicReference;
+
+/**
+ * 读写锁实现-可重入锁
+ *
+ * @author binbin.hou
+ * @since 0.0.2
+ */
+public class LockReadWriteRe {
+
+ private static final Log log = LogFactory.getLog(LockReadWriteRe.class);
+
+ /**
+ * 如果使用类似 write 的方式,会导致读锁只能有一个。
+ * 调整为使用 HashMap 存放读的信息
+ *
+ * @since 0.0.2
+ */
+ private final Map readCountMap = new HashMap<>();
+
+ /**
+ * volatile 引用,保证线程间的可见性+易变性
+ *
+ * @since 0.0.2
+ */
+ private final AtomicReference writeOwner = new AtomicReference<>();
+
+ /**
+ * 写次数统计
+ */
+ private int writeCount = 0;
+
+ /**
+ * 获取读锁,读锁在写锁不存在的时候才能获取
+ *
+ * @since 0.0.2
+ */
+ public synchronized void lockRead() throws InterruptedException {
+ // 写锁存在,需要wait
+ while (!tryLockRead()) {
+ log.debug("获取读锁失败,进入等待状态。");
+ wait();
+ }
+ }
+
+ /**
+ * 尝试获取读锁
+ *
+ * 读锁之间是不互斥的,这里后续需要优化。
+ *
+ * @return 是否成功
+ * @since 0.0.2
+ */
+ private boolean tryLockRead() {
+ if (writeCount > 0) {
+ log.debug("当前有写锁,获取读锁失败");
+ return false;
+ }
+
+ Thread currentThread = Thread.currentThread();
+ Integer count = readCountMap.get(currentThread);
+ if(count == null) {
+ count = 0;
+ }
+ count++;
+
+ this.readCountMap.put(currentThread, count);
+ return true;
+ }
+
+ /**
+ * 释放读锁
+ *
+ * @since 0.0.2
+ */
+ public synchronized void unlockRead() {
+ Thread currentThread = Thread.currentThread();
+ Integer readCount = readCountMap.get(currentThread);
+
+ if (readCount == null) {
+ throw new RuntimeException("当前线程未持有任何读锁,释放锁失败!");
+ } else {
+ readCount--;
+
+ // 已经是最后一次
+ if(readCount == 0) {
+ readCountMap.remove(currentThread);
+ } else {
+ readCountMap.put(currentThread, readCount);
+ }
+
+ log.debug("释放读锁,唤醒所有等待线程。");
+ notifyAll();
+ }
+ }
+
+ /**
+ * 获取写锁
+ *
+ * @since 0.0.2
+ */
+ public synchronized void lockWrite() throws InterruptedException {
+ // 写锁存在,需要wait
+ while (!tryLockWrite()) {
+ log.debug("获取写锁失败,进入等待状态。");
+ wait();
+ }
+
+ // 此时已经不存在获取写锁的线程了,因此占坑,防止写锁饥饿
+ writeCount++;
+ }
+
+ /**
+ * 尝试获取写锁
+ *
+ * @return 是否成功
+ * @since 0.0.2
+ */
+ private boolean tryLockWrite() {
+ if (writeCount > 0) {
+ log.debug("当前有其他写锁,获取写锁失败");
+ return false;
+ }
+
+ // 读锁
+ if (!readCountMap.isEmpty()) {
+ log.debug("当前有其他读锁,获取写锁失败。");
+ return false;
+ }
+
+ Thread currentThread = Thread.currentThread();
+ // 多次重入
+ if(writeOwner.get() == currentThread) {
+ log.debug("为当前写线程多次重入,直接返回 true。");
+ return true;
+ }
+
+ boolean result = writeOwner.compareAndSet(null, currentThread);
+ log.debug("尝试获取写锁结果:{}", result);
+ return result;
+ }
+
+ /**
+ * 释放写锁
+ *
+ * @since 0.0.2
+ */
+ public synchronized void unlockWrite() {
+ Thread currentThread = Thread.currentThread();
+ // 多次重入释放(当次数多于1时直接返回,否则需要释放 owner 信息)
+ if(writeCount > 1 && (currentThread == writeOwner.get())) {
+ log.debug("当前为写锁释放多次重入,直接返回成功。");
+
+ unlockWriteNotify();
+ return;
+ }
+
+ boolean toNullResult = writeOwner.compareAndSet(currentThread, null);
+ if (toNullResult) {
+ unlockWriteNotify();
+ } else {
+ throw new RuntimeException("释放写锁失败");
+ }
+ }
+
+ /**
+ * 释放写锁并且通知
+ */
+ private void unlockWriteNotify() {
+ writeCount--;
+ log.debug("释放写锁成功,唤醒所有等待线程。");
+ notifyAll();
+ }
+
+}
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
index 739698a..bb5b595 100644
--- 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
@@ -1,6 +1,8 @@
package com.github.houbb.lock.redis.core;
import com.github.houbb.lock.redis.exception.LockRuntimeException;
+import com.github.houbb.log.integration.core.Log;
+import com.github.houbb.log.integration.core.LogFactory;
import java.util.concurrent.atomic.AtomicReference;
@@ -11,6 +13,8 @@ import java.util.concurrent.atomic.AtomicReference;
*/
public class LockWaitNotify extends AbstractLock {
+ private static final Log log = LogFactory.getLog(LockWaitNotify.class);
+
/**
* volatile 引用,保证线程间的可见性+易变性
*
@@ -22,6 +26,7 @@ public class LockWaitNotify extends AbstractLock {
public synchronized void lock() {
while (!tryLock()) {
try {
+ log.debug("等待被唤醒");
wait();
} catch (InterruptedException e) {
e.printStackTrace();
@@ -34,7 +39,9 @@ public class LockWaitNotify extends AbstractLock {
public boolean tryLock(String key) {
Thread current = Thread.currentThread();
// CAS
- return owner.compareAndSet(null, current);
+ boolean result = owner.compareAndSet(null, current);
+ log.debug("尝试获取锁结果:{}", result);
+ return result;
}
@Override
@@ -46,7 +53,8 @@ public class LockWaitNotify extends AbstractLock {
}
// 唤醒等待中的线程
- notifyAll();
+ log.debug("唤醒等待的进程");
+ notify();
}
}
diff --git a/lock-core/src/main/java/com/github/houbb/lock/redis/core/LockWaitNotifyRe.java b/lock-core/src/main/java/com/github/houbb/lock/redis/core/LockWaitNotifyRe.java
new file mode 100644
index 0000000..7032f76
--- /dev/null
+++ b/lock-core/src/main/java/com/github/houbb/lock/redis/core/LockWaitNotifyRe.java
@@ -0,0 +1,88 @@
+package com.github.houbb.lock.redis.core;
+
+import com.github.houbb.lock.redis.exception.LockRuntimeException;
+import com.github.houbb.log.integration.core.Log;
+import com.github.houbb.log.integration.core.LogFactory;
+
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicReference;
+
+/**
+ * 等待通知的锁实现-可重入
+ * @author binbin.hou
+ * @since 0.0.2
+ */
+public class LockWaitNotifyRe extends AbstractLock {
+
+ private static final Log log = LogFactory.getLog(LockWaitNotifyRe.class);
+
+ /**
+ * volatile 引用,保证线程间的可见性+易变性
+ *
+ * @since 0.0.2
+ */
+ private AtomicReference owner =new AtomicReference<>();
+
+ /**
+ * 次数统计
+ * @since 0.0.2
+ */
+ private AtomicInteger count = new AtomicInteger(0);
+
+ @Override
+ public synchronized void lock() {
+ while (!tryLock()) {
+ try {
+ log.debug("等待被唤醒");
+ wait();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ // 是否可以被打断
+ }
+ }
+ }
+
+ @Override
+ public boolean tryLock(String key) {
+ Thread current = Thread.currentThread();
+
+ //可重入实现
+ if(current == owner.get()) {
+ count.incrementAndGet();
+ log.debug("当前线程已经拥有锁,直接返回 true");
+ return true;
+ }
+
+ // CAS
+ boolean result = owner.compareAndSet(null, current);
+ log.debug("尝试获取锁结果:{}", result);
+ return result;
+ }
+
+ @Override
+ public synchronized void unlock(String key) {
+ Thread current = Thread.currentThread();
+
+ // 可重入实现
+ if(owner.get() == current && count.get() != 0) {
+ count.decrementAndGet();
+ notifyAndLog();
+ return;
+ }
+
+ boolean result = owner.compareAndSet(current, null);
+ if(!result) {
+ throw new LockRuntimeException("解锁失败");
+ }
+
+ notifyAndLog();
+ }
+
+ private void notifyAndLog() {
+ // 唤醒等待中的线程
+ log.debug("唤醒等待的进程");
+ notify();
+ }
+
+}
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
index f2da746..ae64102 100644
--- 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
@@ -1,7 +1,10 @@
package com.github.houbb.lock.test.core;
+import com.github.houbb.heaven.util.util.DateUtil;
import com.github.houbb.lock.api.core.ILock;
import com.github.houbb.lock.redis.core.LockWaitNotify;
+import com.github.houbb.log.integration.core.Log;
+import com.github.houbb.log.integration.core.LogFactory;
import java.util.concurrent.TimeUnit;
@@ -11,26 +14,19 @@ import java.util.concurrent.TimeUnit;
*/
public class LockWaitNotifyThread implements Runnable {
+ private static final Log log = LogFactory.getLog(LockWaitNotifyThread.class);
+
private final ILock lock = new LockWaitNotify();
@Override
public void run() {
- System.out.println("first-lock: " + Thread.currentThread().getId());
+ log.debug("first lock");
+
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();
- }
+ log.info("执行业务逻辑。");
+ DateUtil.sleep(TimeUnit.SECONDS, 5);
lock.unlock();
- System.out.println("first-unlock: " + Thread.currentThread().getId());
+ log.debug("first unlock");
}
public static void main(String[] args) {
diff --git a/lock-test/src/main/java/com/github/houbb/lock/test/core/LockWaitNotifyThread2.java b/lock-test/src/main/java/com/github/houbb/lock/test/core/LockWaitNotifyThread2.java
new file mode 100644
index 0000000..2228c10
--- /dev/null
+++ b/lock-test/src/main/java/com/github/houbb/lock/test/core/LockWaitNotifyThread2.java
@@ -0,0 +1,45 @@
+package com.github.houbb.lock.test.core;
+
+import com.github.houbb.heaven.util.util.DateUtil;
+import com.github.houbb.lock.api.core.ILock;
+import com.github.houbb.lock.redis.core.LockWaitNotify;
+import com.github.houbb.log.integration.core.Log;
+import com.github.houbb.log.integration.core.LogFactory;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * @author binbin.hou
+ * @since 1.0.0
+ */
+public class LockWaitNotifyThread2 implements Runnable {
+
+ private static final Log log = LogFactory.getLog(LockWaitNotifyThread2.class);
+
+ private final ILock lock = new LockWaitNotify();
+
+ @Override
+ public void run() {
+ log.debug("first lock");
+
+ lock.lock();
+
+ log.debug("second lock");
+ lock.lock();
+ log.info("执行业务逻辑。");
+ DateUtil.sleep(TimeUnit.SECONDS, 5);
+ log.debug("second unlock");
+ lock.unlock();
+
+ lock.unlock();
+ log.debug("first unlock");
+ }
+
+ public static void main(String[] args) {
+ final Runnable runnable = new LockWaitNotifyThread2();
+ 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/LockWaitNotifyThreadRe.java b/lock-test/src/main/java/com/github/houbb/lock/test/core/LockWaitNotifyThreadRe.java
new file mode 100644
index 0000000..ed98224
--- /dev/null
+++ b/lock-test/src/main/java/com/github/houbb/lock/test/core/LockWaitNotifyThreadRe.java
@@ -0,0 +1,43 @@
+package com.github.houbb.lock.test.core;
+
+import com.github.houbb.heaven.util.util.DateUtil;
+import com.github.houbb.lock.api.core.ILock;
+import com.github.houbb.lock.redis.core.LockWaitNotify;
+import com.github.houbb.lock.redis.core.LockWaitNotifyRe;
+import com.github.houbb.log.integration.core.Log;
+import com.github.houbb.log.integration.core.LogFactory;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * @author binbin.hou
+ * @since 1.0.0
+ */
+public class LockWaitNotifyThreadRe implements Runnable {
+
+ private static final Log log = LogFactory.getLog(LockWaitNotifyThreadRe.class);
+
+ private final ILock lock = new LockWaitNotifyRe();
+
+ @Override
+ public void run() {
+ log.debug("first lock");
+ lock.lock();
+
+ log.debug("second lock");
+ lock.lock();
+ log.debug("second unlock");
+ lock.unlock();
+
+ log.debug("first unlock");
+ lock.unlock();
+ }
+
+ public static void main(String[] args) {
+ final Runnable runnable = new LockWaitNotifyThreadRe();
+ new Thread(runnable).start();
+ new Thread(runnable).start();
+ new Thread(runnable).start();
+ }
+
+}
diff --git a/pom.xml b/pom.xml
index d9d15da..d6b073a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -36,6 +36,7 @@
0.1.114
0.0.6
0.0.1
+ 1.1.8
4.12
@@ -72,6 +73,11 @@
wait
${wait.version}
+
+ com.github.houbb
+ log-integration
+ ${log-integration.version}
+