对多线程对订单更新竞争的锁机制的实现-初构

来源:互联网 发布:qq晒米软件 编辑:程序博客网 时间:2024/05/16 12:47

做支付宝支付接入时遇到一个问题,对同一个订单,可能同时存在”支付宝服务器异步通知支付结果更新状态“和“用户主动要求发起查询支付结果更新状态"两个过程。因为在查询要用户已支付订单完成后要向其它系统发起交易请求,所以要求对同一订单,两个过程线程必须在更新时是同步执行的。但如果不区分的对整个更新方法加锁,则并发量又上不去。综合考虑,我决定自行实现一个锁机制,要求加锁后的更新方法做到以下要求:1、对不同的订单,执行更新方法的线程是异步执行的;2、对相同的订单,执行更新方法的线程是同步执行的。

初步的代码实现如下:

import java.util.HashMap;/** * 订单锁,当两个线程同时操作同一个oderNo订单时,进入临界区,不同的oderNo不涉及临界区操作.<br> * <p>Long order=1234l;<br> * try{<br> * OrderLock.lock(oderNo);<br> *  同步代码执行……<br> * }finally{<br> * OrderLock.unlock();<br> * }</p> * <br> * */public class OrderLock {private final static HashMap<Long,ObjectLocker<String>> LockerStore=new HashMap<Long,ObjectLocker<String>>();private final static Object lock=new Object();/** * 尝试进入订单号临界区,其它线程若在其后调用此订单号进入,则等待此线程释放锁后才能进入临界区 * @param oderNo 订单号,若已有其它线程使用相同的订单号调用此方法,则需要等待其它线程调用过unlock方法后才能进入临界区 */public static void lock(String oderNo){ObjectLocker<String> objLoc=null;synchronized (lock) {for(Long id : LockerStore.keySet()){if(LockerStore.get(id).equals(oderNo)){objLoc=LockerStore.get(id);}}if(objLoc==null){objLoc=new ObjectLocker<String>(oderNo);}LockerStore.put(Thread.currentThread().getId(), objLoc);}objLoc.lock();}/** * 解除锁,允许其它线程进入订单临界区 */public static void unlock(){ObjectLocker<String> objLoc=null;synchronized (lock) {objLoc=LockerStore.remove(Thread.currentThread().getId());}if(objLoc!=null){objLoc.unlock();}}/** * 对象锁 * * @param <T> */static class ObjectLocker<T> {private final Object locker = new Object();private final static long nullThread = -1;private long threadId = nullThread;private int requestCount=0;private T target;public ObjectLocker(T target) {super();this.target = target;}@Overridepublic boolean equals(Object obj) {if(target==null){return super.equals(obj);}else{return target.equals(obj);}}public void lock() {synchronized (locker) {requestCount++;do {long currThread=Thread.currentThread().getId();if (currThread == threadId || threadId == nullThread) {threadId = currThread;break;}try {locker.wait();} catch (InterruptedException e) {e.printStackTrace();}} while (true);}}public void unlock() {synchronized (locker) {requestCount--;if (Thread.currentThread().getId() == threadId) {threadId = nullThread;locker.notifyAll();}}}public int getReqeustCount(){return requestCount;}}}


初步的测试代码

import java.util.ArrayList;import java.util.HashMap;
public class LockTest {static HashMap<Long,ArrayList<Long>> cache=new HashMap<Long,ArrayList<Long>>();static class TestThread extends Thread{Long orderNo;public TestThread(Long orderNo) {super();this.orderNo = orderNo;}@Overridepublic void run() {try {sleep(2000l);} catch (InterruptedException e) {e.printStackTrace();}for(int i=0;i<60;++i){try{//System.out.println("线程"+getId()+"等待锁"+orderNo+"……");OrderLock.lock(orderNo.toString());cache.get(orderNo).add(getId());try {sleep(20l);} catch (InterruptedException e) {}//System.out.println("线程"+getId()+"获得锁"+orderNo+"……");} finally{cache.get(orderNo).add(getId());OrderLock.unlock();}//System.out.println("线程"+getId()+"释放锁"+orderNo+"……");try {sleep(20l);} catch (InterruptedException e) {e.printStackTrace();}}}}public static void main(String[] args) {long time0=System.currentTimeMillis();TestThread[] ts=new TestThread[24];cache.put(0l, new ArrayList<Long>());cache.put(1l, new ArrayList<Long>());cache.put(2l, new ArrayList<Long>());cache.put(3l, new ArrayList<Long>());for(int i=0;i<ts.length;++i){ts[i]=new TestThread(i%4l);ts[i].start();}for(int i=0;i<ts.length;++i){try {ts[i].join();} catch (InterruptedException e) {}}System.out.println(System.currentTimeMillis()-time0);for(Long key : cache.keySet()){ArrayList<Long> l=cache.get(key);int len=l.size()/2;for(int i=0;i<len;i++){if(!l.get(2*i).equals(l.get(2*i+1))){System.out.println(2*i);System.out.println(l.get(2*i));System.out.println(l.get(2*i+1));System.out.println(list2String(l));throw new RuntimeException("出现错误");}}//System.out.println(list2String(l));}}static String list2String(ArrayList<Long> l){String tmp="";for(Long i : l){tmp+=i+",";}return tmp;}}



0 0
原创粉丝点击