Spring_Quartz定时器---防止重复处理同一条记录(互
2019-01-18 本文已影响7人
___TheOne___
1.背景
JavaWeb项目经常使用到定时器。如:Spring-Quartz等。
具体使用场景:“APP微信支付”异步获取支付结果:成功 or 失败,定时器异步处理将支付成功的订单,进行承保。
2.问题
定时器的执行频率,可以使用cron表达式指定,比如:每3秒执行一次。
如果执行频率过快,会导致同一条记录被重复处理,出现异常的响应结果。
3.解决方法
Method1:类静态变量---实现互斥锁
伪代码:
public class AJob {
private static boolean isNotRun = true;
public void methodA(){
if(isNotRun){
isNotRun = false;
try{
//do something
}
finally{
isNotRun = true;
}
}//end if
}//end method
}//end class
说明:
1.利用类静态变量isNotRun模拟互斥锁获取,只有isNotRun为true才执行任务方法,否则跳过;
2.获取到之后,在方法执行过程中,将isNotRun设置为false;
3.try-finally使用,保证isNotRun一定可以被释放。
Method2:利用AQS实现类Mutex---实现互斥锁
public class AJob {
private final Lock lock = new MutexLock(); //自定义互斥锁实现
public void methodA(){
if (lock.tryLock()) {
try {
// do something
} finally {
lock.unlock();
}
} //end if
}//end method
}//end class
说明:此用法可确保如果获取了锁, 则会释放锁; 如果未获取锁, 则不会试图将其释放.
附件:MutexLock源码(基于AQS实现互斥锁):
import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
class MutexLock implements Lock, java.io.Serializable {
// Our internal helper class
private static class Sync extends AbstractQueuedSynchronizer {
// Reports whether in locked state
protected boolean isHeldExclusively() {
return getState() == 1;
}
// Acquires the lock if state is zero
public boolean tryAcquire(int acquires) {
assert acquires == 1; // Otherwise unused
if (compareAndSetState(0, 1)) {
setExclusiveOwnerThread(Thread.currentThread());
return true;
}
return false;
}
// Releases the lock by setting state to zero
protected boolean tryRelease(int releases) {
assert releases == 1; // Otherwise unused
if (getState() == 0) throw new IllegalMonitorStateException();
setExclusiveOwnerThread(null);
setState(0);
return true;
}
// Provides a Condition
Condition newCondition() {
return new ConditionObject();
}
// Deserializes properly
private void readObject(ObjectInputStream s)
throws IOException, ClassNotFoundException {
s.defaultReadObject();
setState(0); // reset to unlocked state
}
}
// The sync object does all the hard work. We just forward to it.
private final Sync sync = new Sync();
public void lock() {
sync.acquire(1);
}
public boolean tryLock() {
return sync.tryAcquire(1);
}
public void unlock() {
sync.release(1);
}
public Condition newCondition() {
return sync.newCondition();
}
public boolean isLocked() {
return sync.isHeldExclusively();
}
public boolean hasQueuedThreads() {
return sync.hasQueuedThreads();
}
public void lockInterruptibly() throws InterruptedException {
sync.acquireInterruptibly(1);
}
public boolean tryLock(long timeout, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireNanos(1, unit.toNanos(timeout));
}
}