阻塞隊列集成多線程實例

業務需求注:債券系統,用戶創建委託並見單成交、因爲委託數量較大、見單成交修改數據庫數據較多。在此使用阻塞隊列快速返回成功與否給用戶提升用戶體驗,使用線程加快處理業務速度。

流程:用戶下單--下單驗證和委託數據生成--根據債券code判斷是否存在此code並放入對應的阻塞隊列--存在此code直接放入阻塞隊列,不存在則放入阻塞隊列同時啓動線程--啓動的線程輪訓take阻塞隊列中某一code的數據。(相當於一個code對應一個線程。)以下是代碼:

1、聲明阻塞隊列:

@Service
public class ConcurrentSkipListMapFactory {
    //保存新生委託隊列 key:bondCode,value是阻塞隊列
    public static HashMap<String,LinkedBlockingQueue<BondEntrust>> linkedMap = new HashMap<String,LinkedBlockingQueue<BondEntrust>>();}

2、委託下單是判斷阻塞隊列中是否含有code,含有code直接放入阻塞隊列,不含code,放入阻塞隊列同時啓動一個新線程。注意:必須需要入參bondCode(用途:只處理這一個債券的業務),

try {
    if (null == ConcurrentSkipListMapFactory.linkedMap.get(bondCode)){//不含有code
        baseStrategy.sightDeal(bondCode);//啓動一個線程
        LinkedBlockingQueue<BondEntrust> queue = new LinkedBlockingQueue<BondEntrust>();
        queue.put(bondEntrust);
        ConcurrentSkipListMapFactory.linkedMap.put(bondCode,queue);//放入全局阻塞隊列map中
    }else {
        ConcurrentSkipListMapFactory.linkedMap.get(bondCode).put(bondEntrust);//直接放入map中
    }
} catch (InterruptedException e) {
    e.printStackTrace();
    return renderError("新生委託存放數據失敗");
}

3、創建線程池和生成具體線程的類;一共三個類,注意:必須需要入參bondCode(用途:只處理這一個債券的業務)

package com.bond.match.Thread.strategy;

import com.bond.match.Thread.worker.*;
import org.springframework.stereotype.Service;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
 * 線程任務調度類
 * Date: 2018/1/9 0009
 * Time: 10:40
 * To change this template use File | Settings | File Templates.
 */
@Service
public class BaseStrategy {
    /**
     * Executors 工廠方法
     * Executors.newCachedThreadPool()(無界線程池,可以進行自動線程回收)
     * Executors.newFixedThreadPool(int)(固定大小線程池)
     * Executors.newSingleThreadExecutor()(單個後臺線程)
     */
    public static ExecutorService SETTLEPOOL = Executors.newCachedThreadPool();

    public static ExecutorService SINGLEPOOL = Executors.newSingleThreadExecutor();

    /**
     * 產生多個線程:見單成交使用
     * @param bondCode
     */
    public void sightDeal(String bondCode){
        SETTLEPOOL.execute(new SightDealWorler(bondCode));
    }

}
package com.bond.match.Thread.worker;

import com.bond.match.BondDeal.service.BondDealService;
import com.bond.match.Queue.ConcurrentSkipListMapFactory;
import org.apache.log4j.Logger;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.concurrent.LinkedBlockingQueue;

/**
 * 線程工作類
 * Date: 2018/1/9 0009
 * Time: 10:43
 * To change this template use File | Settings | File Templates.
 */
@Component()
@Scope("prototype")
public class SightDealWorler extends MatchWorker{
    private Logger logger = Logger.getLogger(getClass());

    private String bondCode = "";

    public SightDealWorler(String str){
        this.bondCode=str;
    }

    protected void execute(){
        logger.info("當前線程名稱:"+Thread.currentThread().getName()+"債券代碼:"+bondCode);
        //因線程安全,不能使用Spring注入方式,所以得new一個對象
        //若非得需要使用Spring注入,實現SpringApplicationcontextgetBean方法
        new BondDealService().sightDealTake(bondCode);
    }
}
package com.bond.match.Thread.worker;

import org.apache.log4j.Logger;

/**
 * 線程抽象類
 * Date: 2018/1/9 0009
 * Time: 10:34
 * To change this template use File | Settings | File Templates.
 */
public abstract class MatchWorker extends Thread {
    private Logger logger = Logger.getLogger(getClass());

    public void run()
    {
        before();
        execute();
        after();
    }

    protected abstract void execute();

    protected void before()
    {
        logger.debug("開始執行成交撮合");
    }

    protected void after()
    {
        logger.debug("結束執行成交撮合");
    }

}

4、線程中輪訓執行對應業務

/**
 * 啓動每個bondCode的獲取線程
 * @param bondCode
 */
public void sightDealTake(String bondCode){
    try {
        BondEntrust bondEntrust = new BondEntrust();
        while (true){
            bondEntrust = ConcurrentSkipListMapFactory.linkedMap.get(bondCode).take();
            logger.info("線程獲取隊列queue數據take--bondCode"+bondCode);
            if (null != bondEntrust){
                if (8==bondEntrust.getEntrustState()){//撤單委託
                    ApplicationContextProvider.getBean(BondEntrustService.class).repealBondEntrust(bondEntrust,true);
                }else {//新生委託,需見單成交
                    this.sightDeal(bondEntrust);
                }
            }
        }
    } catch (Exception e) {
        e.printStackTrace();
        logger.info("線程異常、重啓債券線程:--bondCode"+bondCode);
        ApplicationContextProvider.getBean(BaseStrategy.class).sightDeal(bondCode);
    }
}



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