防止併發處理

一. 緩存方式

以下是同個用戶同時提交多個問題時的防併發處理

<span style="font-size:18px;">String simultaneouslyKey = "_key_simultaneously_"+loginAccount.getAccountId();
	Object obj = cacheClient.get(simultaneouslyKey);
	if (obj == null) {
		cacheClient.set(simultaneouslyKey, 1, new Date(System.currentTimeMillis() + 5000));
	} else {
		if(1 == (Integer)obj){
			json.put("ret", -1);
			json.put("msg", "您提交太頻繁,請稍後提交");
			out.println(json.toString());
			return ;
		}
	}</span>

緩存方式在分佈式環境下依然會出現併發的問題,下面介紹同步鎖的方式,在分佈式環境下同樣有效

二. 同步鎖方式

以下是同步鎖的兩個工具類:

<span style="font-size:18px;">public class McSyncUtils {

	/**
	 * 使用mc的併發CAS模式執行一段在分佈式環境中需要同步的代碼
	 * @param mcc
	 * @param mutexKey  同步鎖的key
	 * @param event  同步處理事件
	 * @param mustExecSuccess  是否每個線程都必須等待執行success()方法,如果爲false則表示第一次獲取失敗之後再也不等待繼續執行了
	 * @throws InterruptedException
	 * void
	 * @author
	 * @update date 
	 */
    public static void execSyncCode(MemCachedClient mcc, String mutexKey, 
            SyncEvent event, boolean mustExecSuccess) throws InterruptedException{
        String currentValue = System.currentTimeMillis() + "";
        
        // 添加互斥鎖,最長鎖10秒鐘
        if(mcc.add(mutexKey, currentValue, new java.util.Date(10 * 1000))){
        	String val = mcc.get(mutexKey).toString();
        	
        	if(currentValue.equals(val)){
	            if(event.syncCondition()){
	                event.success();
	            } else {
	                event.failure();
	            }
	            // 取消互斥鎖
	            mcc.delete(mutexKey);	            
	            return;
        	}
        }
        
        // 該互斥鎖已經被其他線程佔用
        if(mustExecSuccess){
            // 等待獲取鎖資源
            Thread.sleep(50);
            // 重複執行
            execSyncCode(mcc, mutexKey, event, mustExecSuccess);
        } else {
            event.failure();
        }
    }
      
}</span>

<span style="font-size:18px;">/**
 * 
 * 同步處理事件,獲得執行機會後執行sucess()方法,獲取失敗則執行failure()方法
 * @author 
 * @create date 
 */
public interface SyncEvent {
    /**
     * 執行同步業務代碼的條件,滿足該條件的時候纔會進行獲取鎖執行success()中的代碼
     */
    boolean syncCondition();

    /**
     * 獲取到同步鎖之後執行的事件
     */
    void success();

    /***
     * 獲取同步鎖失敗或者沒進行獲取同步鎖的時候執行的事件
     */
    void failure();
}</span>

案例:

<span style="font-size:18px;">   try {
    	    final MemCachedClient mcc = env.getBean("mcc", MemCachedClient.class);
            final String key = "exchangeGift2_" + giftId + "_" + accountId + "_" + mag;
            final String mutexKey = "exchangeGift2_" + giftId + "_" + accountId + "_" + mag + "_mutexkey";
	    McSyncUtils.execSyncCode(mcc, mutexKey, new SyncEvent(){
		@Override
		public boolean syncCondition(){
		// 如果該投票對應的key不存在則獲取鎖進行執行
	          return mcc.get(key) == null;
		}
		@Override
		public void success(){
		  mcc.set(key, "1", new java.util.Date(2 * 1000L));//2秒時間內對一個用戶只能領取一次
		}
			    
	        @Override
		public void failure(){
		  throw new CoinException(111, "請稍後再來申請");
		}
			    
	     }, false);
         } catch (InterruptedException e1) {
	    throw new CoinException(111, "請稍後再來申請");
     }</span>




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章