只供自己使用
http://www.kafka.cc/archives/255.html
业务需求注:债券系统,用户创建委托并见单成交、因为委托数量较大、见单成交修改数据库数据较多。在此使用阻塞队列快速返回成功与否给用户提升用户体验,使用线程加快处理业务速度。
流程:用户下单--下单验证和委托数据生成--根据债券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注入,实现Spring的Applicationcontext中getBean方法
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);
}
}