Skip to content

Commit 458f1d9

Browse files
committed
version 0.8.1.0 update
完善写锁,提供最长等待时间,最长执行时间,是否强制执行等属性,全方位避免死锁
1 parent 9d81db6 commit 458f1d9

File tree

11 files changed

+154
-30
lines changed

11 files changed

+154
-30
lines changed

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,4 +73,7 @@
7373
<tr>
7474
<td>0.8.0.0</td><td>完善读锁,提供最长等待时间,最长执行时间,是否强制执行等属性,全方位避免死锁</td><td>2022年2月4日</td>
7575
</tr>
76+
<tr>
77+
<td>0.8.1.0</td><td>完善写锁,提供最长等待时间,最长执行时间,是否强制执行等属性,全方位避免死锁</td><td>2022年2月4日</td>
78+
</tr>
7679
</table>

src/main/java/org/springframework/lock/annotation/WriteLock.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,28 @@
1919
* @return 默认null,如果有自定义值则覆盖默认值
2020
*/
2121
BooleanEnum fair() default NULL;
22+
23+
/**
24+
* 等待时长,没获得锁的时候最多等待多长时间
25+
* @return 默认最多等待Long.MAX_VALUE
26+
*/
27+
long waitTime() default Long.MAX_VALUE;
28+
29+
/**
30+
* 执行时长,超过此时间无论有没有执行完毕都要释放锁
31+
* @return 默认Long.MAX_VALUE
32+
*/
33+
long executeTime() default Long.MAX_VALUE;
34+
35+
/**
36+
* 是否强制执行,如果等待时间耗尽还没有拿到锁的话,是否还要执行
37+
* @return 默认放弃
38+
*/
39+
boolean isContinueIfElapsed() default false;
40+
41+
/**
42+
* 如果强制执行,是否中断其他线程以强制获得锁
43+
* @return 默认否
44+
*/
45+
boolean withLockIfContinue() default false;
2246
}

src/main/java/org/springframework/lock/annotation/package-info.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,6 @@
33
* 每个注解上都有对应的注释,写得很清楚,自己看就可以了,不加以赘述.
44
* 需要注意的是,如果需要使锁注解生效,需要在springboot启动类上添加{@code @EnableSpringLocks}注解
55
* @author 宗祥瑞
6-
* @version 0.8.0.0
6+
* @version 0.8.1.0
77
*/
88
package org.springframework.lock.annotation;

src/main/java/org/springframework/lock/aspect/ReadLockAspect.java

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
import java.util.concurrent.locks.ReentrantReadWriteLock;
1616

1717
import static java.util.concurrent.TimeUnit.*;
18-
import static java.util.concurrent.locks.ReentrantReadWriteLock.*;
1918

2019
/**
2120
* 用于处理读锁的切面
@@ -39,26 +38,21 @@ public Object aroundReadLock(ProceedingJoinPoint jp) throws Throwable {
3938
Object obj = jp.getTarget();
4039
Class<?> clz = obj.getClass();
4140
Lock readLock = null;
42-
Lock writeLock = null;
4341
ReentrantReadWriteLock lock = null;
4442
for (Field field : clz.getDeclaredFields()) {
4543
if ("$readLock".equals(field.getName())){
4644
field.setAccessible(true);
4745
readLock = (Lock) field.get(obj);
4846
}
49-
if ("$writeLock".equals(field.getName())){
50-
field.setAccessible(true);
51-
writeLock = (Lock) field.get(obj);
52-
}
5347
if ("$lock".equals(field.getName())){
5448
field.setAccessible(true);
5549
lock = (ReentrantReadWriteLock) field.get(obj);
5650
}
57-
if (lock != null && readLock != null && writeLock != null)
51+
if (lock != null && readLock != null)
5852
// 都找到了
5953
break;
6054
}
61-
if (readLock == null || lock == null || writeLock == null){
55+
if (readLock == null || lock == null){
6256
// 连锁都没拿到,说明编译期间出了问题
6357
LOGGER.warn(clz.getSimpleName() + "编译时生成读写锁锁失败,未能加锁");
6458
return jp.proceed();
@@ -95,10 +89,16 @@ public Object aroundReadLock(ProceedingJoinPoint jp) throws Throwable {
9589
Method getOwner = ReentrantReadWriteLock.class.getDeclaredMethod("getOwner");
9690
getOwner.setAccessible(true);
9791
Thread lockedThread = (Thread) getOwner.invoke(lock);
98-
lockedThread.stop();
99-
LOGGER.warn("等待时间耗尽,终止线程" + lockedThread + "以强制获得锁");
92+
lockedThread.interrupt();
10093
if (readLock.tryLock(waitTime, MILLISECONDS)){
94+
LOGGER.warn("等待时间耗尽,终止线程" + lockedThread + "以强制获得锁");
10195
result = this.processMethod(jp, readLock, executeTime);
96+
}else{
97+
lockedThread.stop();
98+
if (readLock.tryLock(waitTime, MILLISECONDS)){
99+
LOGGER.warn("等待时间耗尽,终止线程" + lockedThread + "以强制获得锁");
100+
result = this.processMethod(jp, readLock, executeTime);
101+
}
102102
}
103103
}else {
104104
LOGGER.warn("等待时间耗尽,将不带锁执行" + method.getName());

src/main/java/org/springframework/lock/aspect/WriteLockAspect.java

Lines changed: 90 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,16 @@
55
import org.aspectj.lang.ProceedingJoinPoint;
66
import org.aspectj.lang.annotation.Around;
77
import org.aspectj.lang.annotation.Aspect;
8+
import org.aspectj.lang.reflect.MethodSignature;
9+
import org.springframework.lock.annotation.WriteLock;
10+
import org.springframework.lock.timer.InterruptTimer;
811

912
import java.lang.reflect.Field;
13+
import java.lang.reflect.Method;
1014
import java.util.concurrent.locks.Lock;
15+
import java.util.concurrent.locks.ReentrantReadWriteLock;
16+
17+
import static java.util.concurrent.TimeUnit.MILLISECONDS;
1118

1219
/**
1320
* 用于处理写锁的切面
@@ -31,28 +38,98 @@ public Object aroundWriteLock(ProceedingJoinPoint jp) throws Throwable {
3138
Object obj = jp.getTarget();
3239
Class<?> clz = obj.getClass();
3340
Lock writeLock = null;
41+
ReentrantReadWriteLock lock = null;
3442
for (Field field : clz.getDeclaredFields()) {
3543
if ("$writeLock".equals(field.getName())){
3644
field.setAccessible(true);
37-
Object unknownLock = field.get(obj);
38-
writeLock = (Lock) unknownLock;
45+
writeLock = (Lock) field.get(obj);
46+
}
47+
if ("$lock".equals(field.getName())){
48+
field.setAccessible(true);
49+
lock = (ReentrantReadWriteLock) field.get(obj);
3950
}
51+
if (lock != null && writeLock != null)
52+
// 都找到了
53+
break;
4054
}
55+
if (lock == null || writeLock == null){
56+
// 连锁都没拿到,说明编译期间出了问题
57+
LOGGER.warn(clz.getSimpleName() + "编译时生成读写锁锁失败,未能加锁");
58+
return jp.proceed();
59+
}
60+
61+
long waitTime = Long.MAX_VALUE;
62+
long executeTime = Long.MAX_VALUE;
63+
boolean isContinueIfElapsed = false;
64+
boolean withLockIfContinue = false;
65+
66+
MethodSignature signature = (MethodSignature) jp.getSignature();
67+
Method method = signature.getMethod();
68+
if (method == null) {
69+
// 没拿到方法,那注解给了谁呢?
70+
LOGGER.warn("没拿到方法" + signature);
71+
return jp.proceed();
72+
}
73+
WriteLock annotation = method.getAnnotation(WriteLock.class);
74+
if (annotation != null) {
75+
waitTime = annotation.waitTime();
76+
executeTime = annotation.executeTime();
77+
isContinueIfElapsed = annotation.isContinueIfElapsed();
78+
withLockIfContinue = annotation.withLockIfContinue();
79+
}
80+
4181
Object result = null;
42-
if (writeLock != null) {
43-
writeLock.lock();
44-
LOGGER.info(clz.getSimpleName() + "获得写锁");
45-
try {
46-
result = jp.proceed();
47-
} finally {
48-
writeLock.unlock();
49-
LOGGER.info(clz.getSimpleName() + "释放写锁");
50-
}
82+
boolean locked = writeLock.tryLock(waitTime, MILLISECONDS);
83+
if (locked) {
84+
result = this.processMethod(jp, writeLock, executeTime);
5185
}else {
52-
LOGGER.warn(clz.getSimpleName() + "生成读锁失败,未能加锁");
53-
result = jp.proceed();
86+
if (isContinueIfElapsed){
87+
if (withLockIfContinue){
88+
// 解别人锁的逻辑,这是终极大招
89+
Method getOwner = ReentrantReadWriteLock.class.getDeclaredMethod("getOwner");
90+
getOwner.setAccessible(true);
91+
Thread lockedThread = (Thread) getOwner.invoke(lock);
92+
lockedThread.interrupt();
93+
if (writeLock.tryLock(waitTime, MILLISECONDS)){
94+
LOGGER.warn("等待时间耗尽,中断线程" + lockedThread + "以强制获得锁");
95+
result = this.processMethod(jp, writeLock, executeTime);
96+
}else {
97+
lockedThread.stop();
98+
if (writeLock.tryLock(waitTime, MILLISECONDS)) {
99+
LOGGER.warn("等待时间耗尽,终止线程" + lockedThread + "以强制获得锁");
100+
result = this.processMethod(jp, writeLock, executeTime);
101+
}
102+
}
103+
}else {
104+
LOGGER.warn("等待时间耗尽,将不带锁执行" + method.getName());
105+
result = jp.proceed();
106+
}
107+
}else {
108+
LOGGER.warn("等待时间耗尽,放弃执行" + method.getName());
109+
}
54110
}
55111
return result;
56112
}
57113

114+
115+
/**
116+
* 处理方法的过程
117+
* @param jp 切入点
118+
* @param writeLock 写锁,在调用方法前必须加锁
119+
* @param executeTime 最大执行时长
120+
* @return 原方法返回值
121+
* @throws Throwable 异常
122+
*/
123+
private Object processMethod(ProceedingJoinPoint jp, Lock writeLock, long executeTime) throws Throwable {
124+
Object result = null;
125+
LOGGER.info(Thread.currentThread().getName() + "获得写锁");
126+
new InterruptTimer(Thread.currentThread(), executeTime);
127+
try {
128+
result = jp.proceed();
129+
} finally {
130+
writeLock.unlock();
131+
LOGGER.info(Thread.currentThread().getName() + "释放写锁");
132+
}
133+
return result;
134+
}
58135
}

src/main/java/org/springframework/lock/aspect/package-info.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,6 @@
33
* 每个切面都有注释,没什么好说的,不加以赘述.
44
* 切面这部分需要托管到spring容器中去执行.
55
* @author 宗祥瑞
6-
* @version 0.8.0.0
6+
* @version 0.8.1.0
77
*/
88
package org.springframework.lock.aspect;
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/**
22
* 这是关于枚举类型的包.
33
* 写得很清楚,直接看代码就好了.
4-
* @version 0.8.0.0
4+
* @version 0.8.1.0
55
* @author 宗祥瑞
66
*/
77
package org.springframework.lock.enumeration;

src/main/java/org/springframework/lock/processor/package-info.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,6 @@
44
* 它的原理与lombok有些许类似,但代码风格比lombok更好理解,一看就懂
55
* 每个处理器都写了注释,写得都很清楚,不加以赘述
66
* @author 宗祥瑞
7-
* @version 0.8.0.0
7+
* @version 0.8.1.0
88
*/
99
package org.springframework.lock.processor;

src/main/java/org/springframework/lock/timer/package-info.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,6 @@
33
* 意思就是在多长时间后执行什么功能,或者要求每过多长时间执行什么功能.
44
* java不能多继承,所以用内部类来实现
55
* @author 宗祥瑞
6-
* @version 0.8.0.0
6+
* @version 0.8.1.0
77
*/
88
package org.springframework.lock.timer;

src/test/java/example/name/controller/BaseController.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,13 @@ public String testReadLock(){
2828
return result;
2929
}
3030

31+
@RequestMapping(value = "/testWriteLock2", method = RequestMethod.GET)
32+
@ResponseBody
33+
public String testWriteLock2(){
34+
String result = this.baseService.testWriteLock2();
35+
return result;
36+
}
37+
3138
@RequestMapping(value = "/testWriteLock", method = RequestMethod.GET)
3239
@ResponseBody
3340
public String testWriteLock(){

0 commit comments

Comments
 (0)