77import org .aspectj .lang .annotation .Aspect ;
88import org .aspectj .lang .reflect .MethodSignature ;
99import org .springframework .lock .annotation .OptimisticLock ;
10+ import org .springframework .lock .timer .InterruptTimer ;
11+ import org .springframework .util .StringUtils ;
1012
1113import java .lang .reflect .Field ;
1214import java .lang .reflect .Method ;
1315import java .util .concurrent .atomic .AtomicBoolean ;
16+ import java .util .concurrent .atomic .AtomicLong ;
1417
1518import static java .lang .Thread .sleep ;
19+ import static java .util .concurrent .TimeUnit .MILLISECONDS ;
1620
1721/**
1822 * 乐观锁的切面
@@ -33,48 +37,143 @@ public class OptimisticLockAspect {
3337 */
3438 @ Around ("@annotation(org.springframework.lock.annotation.OptimisticLock)" )
3539 public Object aroundOptimisticLock (ProceedingJoinPoint jp ) throws Throwable {
36- Object obj = jp .getTarget ();
37- Class <?> clz = obj .getClass ();
38- // 获取等待时长,默认500毫秒
39- long waitTime = 500L ;
40+ // 获取注解属性值
41+ long pollingTime = 500L ;
42+ long waitTime = Long .MAX_VALUE ;
43+ long executeTime = Long .MAX_VALUE ;
44+ boolean isContinueIfElapsed = false ;
45+ boolean withLockIfContinue = false ;
46+ String lockName = null ;
47+
4048 MethodSignature signature = (MethodSignature ) jp .getSignature ();
4149 Method method = signature .getMethod ();
42- if (method != null ) {
43- OptimisticLock annotation = method .getAnnotation (OptimisticLock .class );
44- if (annotation != null ) {
45- waitTime = annotation .value ();
46- }
50+ OptimisticLock annotation = method .getAnnotation (OptimisticLock .class );
51+ if (annotation != null ) {
52+ pollingTime = annotation .pollingTime ();
53+ waitTime = annotation .waitTime ();
54+ executeTime = annotation .executeTime ();
55+ isContinueIfElapsed = annotation .isContinueIfElapsed ();
56+ withLockIfContinue = annotation .withLockIfContinue ();
57+ lockName = annotation .value ();
4758 }
59+
4860 // 获取锁对象
49- AtomicBoolean lock = null ;
50- for (Field field : clz .getDeclaredFields ()) {
51- if ("$opLock" .equals (field .getName ())){
52- field .setAccessible (true );
53- Object unknownLock = field .get (obj );
54- lock = (AtomicBoolean ) unknownLock ;
55- }
61+ AtomicLong lock = null ;
62+ Object obj = jp .getTarget ();
63+ Class <?> clz = obj .getClass ();
64+ Field field = null ;
65+
66+ if (StringUtils .hasText (lockName )){
67+ field = clz .getDeclaredField (lockName );
68+ field .setAccessible (true );
69+ lock = (AtomicLong ) field .get (obj );
70+ }else {
71+ field = clz .getDeclaredField ("$opLock" );
72+ field .setAccessible (true );
73+ lock = (AtomicLong ) field .get (obj );
74+ }
75+
76+ if (lock == null ){
77+ LOGGER .warn (clz .getSimpleName () + "获取锁错误,请检查锁名称是否正确" );
78+ return jp .proceed ();
5679 }
80+
81+ // 尝试加锁,不行就解掉别人的锁
5782 Object result = null ;
58- if (lock != null ){
59- while (true ){
60- if (lock .compareAndSet (true , false ))
61- // 拿到了锁
62- break ;
63- else
64- // 如果没拿到锁就忙等待
65- sleep (waitTime );
83+ boolean locked = this .tryLock (lock , waitTime , pollingTime );
84+ if (locked ){
85+ result = this .processMethod (jp , lock , executeTime );
86+ }else {
87+ if (isContinueIfElapsed ){
88+ if (withLockIfContinue ){
89+ Thread lockedThread = findThread (lock .get ());
90+ if (lockedThread == null )
91+ result = this .processMethod (jp , lock , executeTime );
92+ else {
93+ lockedThread .interrupt ();
94+ if (this .tryLock (lock , waitTime , pollingTime )){
95+ LOGGER .warn ("等待时间耗尽,终止线程" + lockedThread + "以强制获得乐观锁@" + lock .hashCode ());
96+ result = this .processMethod (jp , lock , executeTime );
97+ }else {
98+ lockedThread .stop ();
99+ if (this .tryLock (lock , waitTime , pollingTime )){
100+ LOGGER .warn ("等待时间耗尽,终止线程" + lockedThread + "以强制获得乐观锁@" + lock .hashCode ());
101+ result = this .processMethod (jp , lock , executeTime );
102+ }
103+ }
104+ }
105+ }else {
106+ LOGGER .warn ("等待时间耗尽,将不带锁执行" + method .getName ());
107+ result = jp .proceed ();
108+ }
109+ }else {
110+ LOGGER .warn ("等待时间耗尽,放弃执行" + method .getName ());
66111 }
67- try {
68- LOGGER .info (clz .getSimpleName () + "获得乐观锁" );
69- result = jp .proceed ();
70- LOGGER .info (clz .getSimpleName () + "释放乐观锁" );
71- }finally {
72- lock .set (true );
73- }
74- }else {
75- LOGGER .warn (clz .getSimpleName () + "生成乐观锁失败,未能加锁" );
112+ }
113+ return result ;
114+ }
115+
116+ /**
117+ * 处理方法
118+ * @param jp 切入点
119+ * @param lock 乐观锁,调用方法前必须加锁
120+ * @param executeTime 最长执行时间,超出此时间结束线程
121+ * @return 原方法返回值
122+ * @throws Throwable 异常
123+ */
124+ private Object processMethod (ProceedingJoinPoint jp , AtomicLong lock , long executeTime ) throws Throwable {
125+ Object result = null ;
126+ LOGGER .info (Thread .currentThread ().getName () + "获得乐观锁@" + lock .hashCode ());
127+ if (System .currentTimeMillis () + executeTime > 0 )
128+ new InterruptTimer (Thread .currentThread (), executeTime );
129+ try {
76130 result = jp .proceed ();
131+ } finally {
132+ LOGGER .info (Thread .currentThread ().getName () + "释放乐观锁@" + lock .hashCode ());
133+ lock .set (0 );
77134 }
78135 return result ;
79136 }
137+
138+ /**
139+ * 通过线程id获取线程
140+ * @param threadId 线程id
141+ * @return 线程
142+ */
143+ private static Thread findThread (long threadId ) {
144+ ThreadGroup group = Thread .currentThread ().getThreadGroup ();
145+ while (group != null ) {
146+ Thread [] threads = new Thread [(int )(group .activeCount () * 1.2 )];
147+ int count = group .enumerate (threads , true );
148+ for (int i = 0 ; i < count ; i ++) {
149+ if (threadId == threads [i ].getId ()) {
150+ return threads [i ];
151+ }
152+ }
153+ group = group .getParent ();
154+ }
155+ return null ;
156+ }
157+
158+ /**
159+ * 忙等待,直到超时或获取锁
160+ * @param lock 锁
161+ * @param waitTime 最长等待时长
162+ * @param pollingTime 轮询周期
163+ * @return 是否获得锁
164+ */
165+ private boolean tryLock (AtomicLong lock , long waitTime , long pollingTime ) throws InterruptedException {
166+ long startWaitTime = System .currentTimeMillis ();
167+ while (true ){
168+ if (lock .compareAndSet (0 , Thread .currentThread ().getId ())) {
169+ // 拿到了锁
170+ return true ;
171+ }else if (System .currentTimeMillis () - startWaitTime > waitTime )
172+ // 超时了
173+ return false ;
174+ else
175+ // 如果没拿到锁就忙等待
176+ sleep (pollingTime );
177+ }
178+ }
80179}
0 commit comments