Compare commits
6 Commits
release_0.
...
release_0.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
629c6b8fce | ||
|
|
56e25d67e3 | ||
|
|
67f8b1e2a7 | ||
|
|
acbd8f4022 | ||
|
|
422ec999ac | ||
|
|
71d554ba3b |
@@ -13,4 +13,10 @@
|
||||
|
||||
| 序号 | 变更类型 | 说明 | 时间 | 备注 |
|
||||
|:---|:---|:---|:---|:--|
|
||||
| 1 | A | 基本 api 定义 | 2020-9-2 14:45:40 | |
|
||||
| 1 | A | 基本 api 定义 | 2020-9-2 14:45:40 | |
|
||||
|
||||
# release_0.0.2
|
||||
|
||||
| 序号 | 变更类型 | 说明 | 时间 | 备注 |
|
||||
|:---|:---|:---|:---|:--|
|
||||
| 1 | A | 常见锁添加 | 2020-9-2 14:45:40 | |
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>lock</artifactId>
|
||||
<groupId>com.github.houbb</groupId>
|
||||
<version>0.0.1</version>
|
||||
<version>0.0.2</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -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 {
|
||||
}
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>lock</artifactId>
|
||||
<groupId>com.github.houbb</groupId>
|
||||
<version>0.0.1</version>
|
||||
<version>0.0.2</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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("释放写锁失败");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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 操作实现
|
||||
|
||||
@@ -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<Thread> 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("解锁失败");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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<Thread> 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("解锁失败");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
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;
|
||||
|
||||
/**
|
||||
* 等待通知的锁实现
|
||||
* @author binbin.hou
|
||||
* @since 0.0.2
|
||||
*/
|
||||
public class LockWaitNotify extends AbstractLock {
|
||||
|
||||
private static final Log log = LogFactory.getLog(LockWaitNotify.class);
|
||||
|
||||
/**
|
||||
* volatile 引用,保证线程间的可见性+易变性
|
||||
*
|
||||
* @since 0.0.2
|
||||
*/
|
||||
private AtomicReference<Thread> owner =new AtomicReference<>();
|
||||
|
||||
@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();
|
||||
// CAS
|
||||
boolean result = owner.compareAndSet(null, current);
|
||||
log.debug("尝试获取锁结果:{}", result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void unlock(String key) {
|
||||
Thread current = Thread.currentThread();
|
||||
boolean result = owner.compareAndSet(current, null);
|
||||
if(!result) {
|
||||
throw new LockRuntimeException("解锁失败");
|
||||
}
|
||||
|
||||
// 唤醒等待中的线程
|
||||
log.debug("唤醒等待的进程");
|
||||
notify();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>lock</artifactId>
|
||||
<groupId>com.github.houbb</groupId>
|
||||
<version>0.0.1</version>
|
||||
<version>0.0.2</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.github.houbb.lock.test;
|
||||
|
||||
/**
|
||||
* @author binbin.hou
|
||||
* @since 0.0.1
|
||||
*/
|
||||
public class SyncTest {
|
||||
|
||||
public synchronized void syncOne() {
|
||||
System.out.println("方法1执行");
|
||||
syncTwo();
|
||||
}
|
||||
|
||||
public synchronized void syncTwo() {
|
||||
System.out.println("方法2执行");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
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 LockWaitNotifyThread implements Runnable {
|
||||
|
||||
private static final Log log = LogFactory.getLog(LockWaitNotifyThread.class);
|
||||
|
||||
private final ILock lock = new LockWaitNotify();
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
log.debug("first lock");
|
||||
|
||||
lock.lock();
|
||||
log.info("执行业务逻辑。");
|
||||
DateUtil.sleep(TimeUnit.SECONDS, 5);
|
||||
lock.unlock();
|
||||
log.debug("first unlock");
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
final Runnable runnable = new LockWaitNotifyThread();
|
||||
new Thread(runnable).start();
|
||||
new Thread(runnable).start();
|
||||
new Thread(runnable).start();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
package com.github.houbb.lock.test;
|
||||
@@ -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() {
|
||||
8
pom.xml
8
pom.xml
@@ -5,7 +5,7 @@
|
||||
<groupId>com.github.houbb</groupId>
|
||||
<artifactId>lock</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
<version>0.0.1</version>
|
||||
<version>0.0.2</version>
|
||||
<modules>
|
||||
<module>lock-api</module>
|
||||
<module>lock-core</module>
|
||||
@@ -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>
|
||||
|
||||
@@ -10,9 +10,9 @@ ECHO "============================= RELEASE START..."
|
||||
|
||||
:: 版本号信息(需要手动指定)
|
||||
:::: 旧版本名称
|
||||
SET version=0.0.1
|
||||
SET version=0.0.2
|
||||
:::: 新版本名称
|
||||
SET newVersion=0.0.2
|
||||
SET newVersion=0.0.3
|
||||
:::: 组织名称
|
||||
SET groupName=com.github.houbb
|
||||
:::: 项目名称
|
||||
|
||||
Reference in New Issue
Block a user