彩票后台系统存在大量的异步操作,这些异步操作大多存在类似的共性: 准备数据(生产者)----->执行操作----->操作后处理(作标识).
如:彩票投注
准备数据:搜寻待投注的彩票order
执行操作:到接口代理商去投注
操作后处理:更新我方库标识(通知准备数据的worker下次别再对我已投注,下次别再找我了。或者通知其它的程序,下一步骤可以进行了).
这三个操作当中,执行操作一般涉及到调用外系统的接口,因此耗时是最大的,所以可以考虑使用单生产者多消费者的处理模式.
处理模式简介:
为了更好地实现解耦,由生产者线程worker搜集待处理的数据,组装成Task,然后把Task提交到线程池调度框架,线程池调度器负责根据任务类型把任务提交到不同的线程池中,线程池负责这个任务具体的调度和执行。线程池在执行任务时,根据任务类型找到对应的任务处理器,在任务处理器中定义了任务的执行操作和操作后处理。在这一处理过程中主要包含了四种组件:
生产者worker 负责搜集、组装Task
线程池调度器 负责接收任务,并把任务分配到不同的线程池中(其实起到一个中转器的功能)
线程池 一个增加了功能的线程池,定义了饱和策略、异常处理策略、任务调度执行策略等等。
任务执行器 满足一定接口规范的任务处理器,线程执行任务时不必关心具体细节,只要知道任务对应的任务执行器就OK了。
在这套框架中,线程池、任务执行器与任务存在某种映射关系。通常情况下,一类任务对应一类任务执行器,不同类但特点相同的任务可以投入到同一个线程池中,但是同一类任务不会被调度或者添加到多个线程池中。在这套框架中有如下几个问题需要注意:
(1)同一个任务存在多次被投入线程池中的可能性,即一个任务被投入线程池,但未被执行结束,生产者worker已经开始第二播任务投放了。解决方法有多种,如生产者向线程池投放任务后,保持处理句柄(Future),投入结束后,调用future.get()一直等到投入的所有任务结束后(可以做到框架中),再进行第二播搜集,依次投放。但这样也存在着效率问题,如果这一播任务的某一个处理较慢,生产者worker会一直被阻塞,直到处理完才开始下一播投放。也可以采用其它的方式来处理,如保持任务的线程安全性,即可以同时并发一个任务,只要保证最后的处理结果正确就可以(有点乐观锁的味道),也可以采用的(悲观)锁的方式允许同一任务多重投放,但执行前加锁来确保同一个任务只被执行一次,也可以采用折中的方式,如果在投入任务时,检查缓存队列中是否已经存在此任务,如果存在则丢弃或阻塞(但你必须注意到,有可能线程正在执行任务,这时候你又向线程池中投入任务,即你投入任务时任务已经被执行线程从缓存队列中取出了,当然这种可能性很小)。
(2)良好的任务监控。一个编程习惯良好的程序是不会编写出死循环或类死循环的程序,比如说在HTTP请求处理时,客户端一般会通过设置setConnectionTimeout和setSoTimeout来处理长时间无响应或长时间得不到应答的问题。但是做好监控任务也是很有必要的,毕竟任务执行器对框架是透明的。我们可以对要求任务执行器或任务本身提供一个阀值,来预估这个任务的处理时长,当任务超过这个时长仍未处理结束时发送预警信息。但是收到预警信息后如何在生产环境中干预这种情况呢?从技术的角度,我们是可以取到线程池中处理任务的线程名柄的,并且向线程发送中断信号请求中断信息,但是线程未必就能响应中断,毕竟任务是透明的,并且很大可能是不支持中断的。所以这似乎是个无解。处理方法有如下几种:定位问题重启应用(这只能是最后一招),另一种方法是动态去更改线程池线程数,保证线程池不会因这一个(或几个)任务长时间占有线程而影响到其它的任务也无法处理,但是这种方法也是治标不治本,并且有可能这类任务不停地传送抢占线程,再者就是提供动态的更改线程池的功能,即把和这类任务共用线程池的其它类任务动态地改变切换到别的线程池中去执行。不论如何编写出不带死循环或类死循环的任务是重中之重。
(3)异常处理。为了保证框架的灵活性,我们一般submit(而不是execute)任务,这样可以给调用者提供一个Future,以便客户端可以对任务的执行、取消等有一定的权限,但这样的也存在了一个问题,submit的异常处理不支持UncaughtExceptionHandler的处理机制,这点需要注意.
简易的代码实现如下:
任务(这个任务必须是可比较的)
public class Task<T extends Comparable<? super T>> implements Comparable<Task<T>>{
private int taskId;//任务号
private T taskObject;//任务对象
public int getTaskId() {
return taskId;
}
public void setTaskId(int taskId) {
this.taskId = taskId;
}
public T getTaskObject() {
return taskObject;
}
public void setTaskObject(T taskObject) {
this.taskObject = taskObject;
}
@Override
public int hashCode(){
return taskObject.hashCode()+taskId;
}
@Override
public boolean equals(Object o){
if (o==null) return false;
if (o==this) return true;
if (!(o instanceof Task)) return false;
Task<?> task = (Task<?>)o;
if (this.taskObject.equals(task.taskObject) && this.taskId==task.taskId) return true;
else return false;
}
public int compareTo(Task<T> o) {
if(this.taskId != o.taskId){
throw new RuntimeException("不同类型的task不能进行比较.任务类型:"+this.taskId+" "+o.taskId);
}
return this.taskObject.compareTo(o.getTaskObject());
}
}
线程池调度
public interface ThreadPoolScheduleService {
Future<?> submit(Task<?> task);
}
public class ThreadPoolScheduleServiceImpl implements ThreadPoolScheduleService {
private Map<String,TaskScheduleService> taskScheduleServiceMap;
public Future<?> submit(Task<?> task) {
TaskScheduleService taskScheduleService = taskScheduleServiceMap.get(task.getTaskId()+"");
if(taskScheduleService == null){
throw new RuntimeException("找不到此类任务对应的处理线程池!任务类型:"+task.getTaskId());
}
return taskScheduleService.submit(task);
}
public void setTaskScheduleServiceMap(
Map<String, TaskScheduleService> taskScheduleServiceMap) {
this.taskScheduleServiceMap = taskScheduleServiceMap;
}
public Map<String, TaskScheduleService> getTaskScheduleServiceMap() {
return taskScheduleServiceMap;
}
}
线程池服务(这里的异常处理有问题,不要使用UncaughtExceptionHandler)
public interface TaskScheduleService {
<S extends Comparable<? super S>> Future<?> submit(Task<S> task);
String getMonitorInfo();
}
public class TaskScheduleServiceImpl implements TaskScheduleService {
// private final static Logger logger = Logger.getLogger(TaskScheduleServiceImpl.class);
private String threadPoolName = "unknown";
private int corePoolSize = 1;
private int maximumPoolSize = 5;
private long keepAliveTime = 1;
private int queueSize = 80;
private int threshold = 1*1000*1000;//S
private LotteryThreadPoolExecutor executorService;
private Map<String,TaskProcess<?>> lotteryTaskProcessMap;
public <S extends Comparable<? super S>> Future<?> submit(Task<S> task) {
BlockingQueue<Runnable> queue = executorService.getQueue();
List<Runnable> temp = new ArrayList<Runnable>(queue);
List<Task<?>> list = new ArrayList<Task<?>>();
for(Runnable runnable:temp){
LotteryFutureTask<?> futureTask = (LotteryFutureTask<?>)runnable;
list.add(futureTask.getTask());
}
if(list.contains(task)){
throw new RuntimeException("Task has been in blockQueue!Please wait for a moment to submit.");
}
return executorService.submit(new LotteryTaskCallable<S>(task));
}
//init-method after setProperty
public void init() {
executorService = new LotteryThreadPoolExecutor(
corePoolSize,
maximumPoolSize,
keepAliveTime,
TimeUnit.SECONDS,
new LinkedBlockingQueue<Runnable>(queueSize),
new ThreadFactory(){
public Thread newThread(Runnable runnable) {
return new AppThread(runnable, threadPoolName);
}
},
new ThreadPoolExecutor.AbortPolicy());
}
public void destroy(){
shutdown();
}
public void shutdown(){
if(executorService != null)
//1.唤醒正在等待的任务线程,让他们安全退出
//2.检查是否有活动线程,如果没有了,调用tryInterrupt关闭线程池
//3.如果存在活动线程,则直到最后一个线程安全结束
executorService.shutdown();
}
public List<Runnable> shutdownNow(){
if(executorService != null){
//1.中断等待任务的线程
//2.尽最大努力中断所有正在活动的线程,但需要明确的是并非所有的线程都是可以中断的
//3.返回的是未被执行的任务列表
return executorService.shutdownNow();
}
return Collections.emptyList();
}
public List<Task<?>> getTasksCancelledAtShutdown(){
List<Callable<?>> list = executorService.getCancelledTasks();
List<Task<?>> result = new ArrayList<Task<?>>();
for(Callable<?> callable:list){
LotteryTaskCallable<?> taskCallable = (LotteryTaskCallable<?>)callable;
result.add(taskCallable.getTask());
}
return result;
}
public String getMonitorInfo() {
return "线程池Name:"+threadPoolName+" 主动执行任务的近似线程数:"+executorService.getActiveCount()+" 返回池中的当前线程数:"+executorService.getPoolSize()+"当前队列中剩余容量:"+executorService.getQueue().remainingCapacity()+"线程池队列大小:"+executorService.getQueue().size()+" 返回线程池中曾经的最大线程数:"+executorService.getLargestPoolSize();
}
public class LotteryTaskCallable<T extends Comparable<? super T>> implements Callable<Object>{
private Task<T> task;
public LotteryTaskCallable(Task<T> task){
this.task = task;
}
public Object call() throws Exception {
int type = task.getTaskId();
@SuppressWarnings("unchecked")
TaskProcess<T> taskProcess = (TaskProcess<T>) lotteryTaskProcessMap.get(type+"");
taskProcess.execute(task);
return null;
}
public Task<T> getTask() {
return task;
}
@Override
public int hashCode(){
return task.hashCode();
}
@Override
public boolean equals(Object o){
LotteryTaskCallable<?> callable = (LotteryTaskCallable<?>)o;
return task.equals(callable.getTask());
}
}
private class LotteryThreadPoolExecutor extends ThreadPoolExecutor{
private final Set<Callable<?>> tasksCancelledAtShutdown = Collections.synchronizedSet(new HashSet<Callable<?>>());
private final ThreadLocal<Long> startTime = new ThreadLocal<Long>();
private final AtomicLong numTasks = new AtomicLong();
public LotteryThreadPoolExecutor(int corePoolSize, int maximumPoolSize,long keepAliveTime, TimeUnit unit,BlockingQueue<Runnable> workQueue,ThreadFactory factory, RejectedExecutionHandler handler) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,factory,handler);
}
public List<Callable<?>> getCancelledTasks() {
if (!super.isTerminated())
throw new IllegalStateException("线程池尚未完全关闭!");
return new ArrayList<Callable<?>>(tasksCancelledAtShutdown);
}
@SuppressWarnings("unchecked")
@Override
public <T> Future<T> submit(final Callable<T> callable) {
// return super.submit(new Callable<T>() {
// public T call() throws Exception {
// try {
// return callable.call();
// } finally {
// if (isShutdown()
// && Thread.currentThread().isInterrupted())
// tasksCancelledAtShutdown.add(callable);
// }
// }
// });
return super.submit(new LotteryTaskCallable(((LotteryTaskCallable<?>) callable).getTask()){
public T call() throws Exception {
try {
T t = callable.call();;
return t;
} finally {
if (isShutdown()
&& Thread.currentThread().isInterrupted())
tasksCancelledAtShutdown.add(callable);
}
}
});
}
protected void beforeExecute(Thread t, Runnable r) {
super.beforeExecute(t, r);
startTime.set(System.nanoTime());
}
protected void afterExecute(Runnable r, Throwable t) {//通过参数及源码可以看出,即使任务执行抛出异常,仍会执行afterExecute方法,因此也可以在这里面记录异常日志
try {
long endTime = System.nanoTime();
long taskTime = endTime - startTime.get();
numTasks.incrementAndGet();
if(taskTime > threshold){
// logger.warn(threadPoolName+"处理本次任务耗时:"+taskTime);
System.out.println(threadPoolName+"处理本次任务耗时:"+taskTime);
}
} finally {
super.afterExecute(r, t);
}
}
protected void terminated() {
try {
// logger.info(threadPoolName + "本次共处理任务数:"+numTasks.get());
System.out.println(threadPoolName + "本次共处理任务数:"+numTasks.get());
} finally {
super.terminated();
}
}
@Override
protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
return new LotteryFutureTask<T>(callable);
}
}
private static class LotteryFutureTask<T> extends FutureTask<T>{
Task<?> task;
public LotteryFutureTask(Callable<T> callable) {
super(callable);
LotteryTaskCallable<?> lotteryCallable = (LotteryTaskCallable<?>)callable;
this.task = lotteryCallable.getTask();
}
public Task<?> getTask(){
return task;
}
}
private static class AppThread extends Thread {
public static final String DEFAULT_NAME = "AppThread";
private static final AtomicInteger CREATED = new AtomicInteger();
private static final AtomicInteger ALIVE = new AtomicInteger();
public AppThread(Runnable r){this(r, DEFAULT_NAME);}
public AppThread(Runnable runnable, String name) {
super(runnable, name + "-" + CREATED.incrementAndGet());
// logger.info("创建线程: " + this.getName());
System.out.println("创建线程: " + this.getName());
this.setUncaughtExceptionHandler(
new Thread.UncaughtExceptionHandler() {
public void uncaughtException(Thread t,Throwable e) {
// logger.error("UNCAUGHT in thread " + t.getName(), e);
System.out.println("UNCAUGHT in thread " + t.getName()+ e);
}
});
}
public void run() {
// logger.info("当前活跃线程: "+ALIVE.get());
System.out.println("当前活跃线程: "+ALIVE.get());
try {
ALIVE.incrementAndGet();
long begin = System.currentTimeMillis();
super.run();
long end = System.currentTimeMillis();
if(end - begin > 5000){
// logger.warn(this.getName()+"处理本次任务耗时:"+(end - begin));
System.out.println(this.getName()+"处理本次任务耗时:"+(end - begin));
}
} finally {
ALIVE.decrementAndGet();
}
}
public static int getThreadsCreated() { return CREATED.get(); }
public static int getThreadsAlive() { return ALIVE.get(); }
}
public void setThreadPoolName(String threadPoolName) {
this.threadPoolName = threadPoolName;
}
public void setCorePoolSize(int corePoolSize) {
this.corePoolSize = corePoolSize;
}
public void setMaximumPoolSize(int maximumPoolSize) {
this.maximumPoolSize = maximumPoolSize;
}
public void setKeepAliveTime(long keepAliveTime) {
this.keepAliveTime = keepAliveTime;
}
public void setQueueSize(int queueSize) {
this.queueSize = queueSize;
}
public void setThreshold(int threshold) {
this.threshold = threshold;
}
public void setLotteryTaskProcessMap(
Map<String, TaskProcess<?>> lotteryTaskProcessMap) {
this.lotteryTaskProcessMap = lotteryTaskProcessMap;
}
}
任务执行器
public interface TaskProcess<T extends Comparable<? super T>>{
void execute(Task<T> task) throws Exception;
}
public abstract class AbstractTaskProcess<T extends Comparable<? super T>,P> implements TaskProcess<T> {
public void execute(Task<T> task) throws Exception{
P p = doTask(task);
afterDone(p);
}
public abstract P doTask(Task<T> task)throws Exception;
public abstract void afterDone(P t)throws Exception;
}
public class StringTaskProcess extends AbstractTaskProcess<String,String>{
public String doTask(Task<String> task)throws Exception{
if(true){
throw new RuntimeException("----------------------");
}
Thread.sleep(1000);
String result = task.getTaskObject();
System.out.println("这是第一次调用"+result);
return result;
}
public void afterDone(String str){
System.out.println("这是第二次调用"+str);
}
public static void main(String[] args)throws Exception{
Task<String> task = new Task<String>();
task.setTaskId(1);
task.setTaskObject("This is a first call.");
TaskScheduleServiceImpl taskScheduleService = new TaskScheduleServiceImpl();
HashMap<String, TaskProcess<?>> lotteryTaskProcessMap = new HashMap<String,TaskProcess<?>>();
lotteryTaskProcessMap.put("1", new StringTaskProcess());
taskScheduleService.setLotteryTaskProcessMap(lotteryTaskProcessMap);
taskScheduleService.init();
ThreadPoolScheduleServiceImpl threadPoolSchedule = new ThreadPoolScheduleServiceImpl();
Map<String,TaskScheduleService> taskScheduleServiceMap = new HashMap<String,TaskScheduleService>();
taskScheduleServiceMap.put("1", taskScheduleService);
threadPoolSchedule.setTaskScheduleServiceMap(taskScheduleServiceMap);
threadPoolSchedule.submit(task);
/* List temp = null;
for(int i=0;i<500;i++){
Task<String> task1 = new Task<String>();
task1.setTaskId(1);
task1.setTaskObject("This is a first call."+i);
threadPoolSchedule.submit(task1);
// System.out.println(taskScheduleService.getMonitorInfo());
// if(i==500){
// Thread.sleep(20000);
// }
if(i>50){
Thread.sleep(1000);
System.out.println(taskScheduleService.getMonitorInfo());
temp = taskScheduleService.shutdownNow();
System.out.println(taskScheduleService.getMonitorInfo());
break;
}
}
Thread.sleep(100);
List<Task<?>> list = taskScheduleService.getTasksCancelledAtShutdown();
System.out.println(list.size());
for(Task task2:list){
System.out.println("()()"+task2.getTaskObject());
}
System.out.println(temp.size());*/
}
}