[Feature] add for new

This commit is contained in:
houbb
2020-10-19 23:38:19 +08:00
parent 67f8b1e2a7
commit 56e25d67e3
10 changed files with 645 additions and 16 deletions

View File

@@ -32,6 +32,10 @@
<groupId>com.github.houbb</groupId>
<artifactId>heaven</artifactId>
</dependency>
<dependency>
<groupId>com.github.houbb</groupId>
<artifactId>log-integration</artifactId>
</dependency>
<!--============================== OTHER ==============================-->
<dependency>

View File

@@ -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();
}
}

View File

@@ -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<Thread, Integer> readCountMap = new HashMap<>();
/**
* volatile 引用,保证线程间的可见性+易变性
*
* @since 0.0.2
*/
private final AtomicReference<Thread> 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("释放写锁失败");
}
}
}

View File

@@ -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<Thread, Integer> readCountMap = new HashMap<>();
/**
* volatile 引用,保证线程间的可见性+易变性
*
* @since 0.0.2
*/
private final AtomicReference<Thread> 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();
}
}

View File

@@ -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();
}
}

View File

@@ -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<Thread> 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();
}
}

View File

@@ -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) {

View File

@@ -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();
}
}

View File

@@ -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();
}
}

View File

@@ -36,6 +36,7 @@
<heaven.version>0.1.114</heaven.version>
<id.version>0.0.6</id.version>
<wait.version>0.0.1</wait.version>
<log-integration.version>1.1.8</log-integration.version>
<!--============================== OTHER ==============================-->
<junit.version>4.12</junit.version>
@@ -72,6 +73,11 @@
<artifactId>wait</artifactId>
<version>${wait.version}</version>
</dependency>
<dependency>
<groupId>com.github.houbb</groupId>
<artifactId>log-integration</artifactId>
<version>${log-integration.version}</version>
</dependency>
<!--============================== OTHER ==============================-->
<dependency>