阻塞队列集成多线程实例

业务需求注:债券系统,用户创建委托并见单成交、因为委托数量较大、见单成交修改数据库数据较多。在此使用阻塞队列快速返回成功与否给用户提升用户体验,使用线程加快处理业务速度。

流程:用户下单--下单验证和委托数据生成--根据债券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);
    }
}



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