使用线程池和反射实现异步任务

来源:互联网 发布:知乎live可以事后看吗 编辑:程序博客网 时间:2024/06/05 09:20

    很久没来写东西了,冠冕堂皇的原因就是太忙了,这一年时间负责技术还要负责产品,带领三五个小伙伴做一个互联网系统,实在是累。实际的原因就是太懒了,每次想写点什么,却总是在犹豫中蹉跎。

    最近写了一点代码,和大家分享交流。主要应用场景就是在把业务流程中某些不是太重要却又比较耗时的任务从主流程剥离放到线程池去执行,但这样的场景很多,很分散,又不想为每个场景写专门的处理类,就想使用反射偷点懒,每个被剥离的任务只需要实现一个方法就可以,而不用实现一个类。

调度类实现了一个线程池的调度,大概关键代码如下:

public class Scheduler { private static final Log logger = LogFactory.getLog(Job.class);private static final Scheduler instance = new Scheduler();private static ExecutorService executorServie;  private Scheduler() { executorServie = Executors.newFixedThreadPool(10);}@Bean(name = "Bmall.Scheduler", initMethod = "init", destroyMethod = "shutdown")public static Scheduler getInstance() {return instance;}public void init() {if (start) {this.start();}} public void shutdown() {            ....}  /** * 调用一个任务,返回FutureTask * @param service 可以是bean的名字也可以是bean对象<br/> * @param method  需要执行的方法名<br/> * @param params  执行所需参数<br/> * @return FutureTask对象 * @throws InterruptedException * @throws ExecutionException */public <T> FutureTask<T> call(T service, String method,@SuppressWarnings("unchecked") T ... params) throws InterruptedException, ExecutionException{    FutureTask<T> futureTask = new FutureTask<T>(new AloneTask<T>(service,method,params));executorServie.submit(futureTask);return futureTask;} }

    任务主体类如下:

public class AloneTask<T> implements Callable<T> {private static final Log logger = LogFactory.getLog(AloneTask.class);Object service;String method; Object[] params;public AloneTask(T service, String method,Object ... params) {super();if(service instanceof String){this.service=(Object) SpringHelper.getBean((String) service); }else{this.service = service;} this.method = method;this.params = params;}  @Override@SuppressWarnings("unchecked")public T call() throws Exception {// TODO Auto-generated method stub if(service==null||method==null){ ExceptionHelper.throwExcep("参数异常,无法完成任务.");}long startTime = System.currentTimeMillis();T future=(T) getMethod().invoke(this.service, this.params); long useTime = (startTime - System.currentTimeMillis()) / 1000;if(useTime > 10) {logger.warn("call cost time too long,time "+useTime+"s,task method:" + this.method);}return future;}  /* * 获取被调用的方法 */private Method getMethod(){   Method m=null;        try {   @SuppressWarnings("rawtypes")Class[] paramsClass = new Class[this.params.length];for(int i=0;i<this.params.length;i++){paramsClass[i]=this.params[i].getClass();} m=this.service.getClass().getMethod(this.method, paramsClass);  } catch (Exception e) {// TODO Auto-generated catch blocklogger.info(String.format("not find [%s] method,try scan all method ...",this.method));Method[] allMethods=this.service.getClass().getMethods();for(Method mRec:allMethods){if(mRec.getName().equals(this.method)){Class<?>[] methodParamsTypes = mRec.getParameterTypes();  //找到同名函数的参数类型if(methodParamsTypes.length==this.params.length){boolean flag=true;for(int i=0;i<methodParamsTypes.length;i++){if(null!=this.params[i]){if(!match(this.params[i],methodParamsTypes[i])){flag=false;break;}}}if(flag){m=mRec;break;}}}} }              if(null==m){       ExceptionHelper.throwExcep(String.format("未找[%s]到的[%s]方法完成任务.",this.service.getClass().toString(),this.method));       }return m;}/** * 判断参数类型是否匹配 * @param c  参数类型 * @param pc  方法参数类型 * @return */private boolean match(Object p,Class pc){boolean isMatch=true;if(pc.isPrimitive()){    //方法参数是基本类型 if(!pc.equals(getPrimitiveClass(p.getClass()))){isMatch=false;}}else{if(!pc.isInstance(p)){isMatch=false;}}return isMatch;}private static Class getPrimitiveClass(Class c){Class pc = null;if( c.equals(Long.class) ){pc = long.class;}else if( c.equals(Integer.class) ){pc = int.class;}else if( c.equals(Double.class) ){pc = double.class;}else if( c.equals(Float.class) ){pc = float.class;}else if( c.equals(Short.class) ){pc = short.class;}else if( c.equals(Byte.class) ){pc = byte.class;}else if( c.equals(Character.class) ){pc = char.class;}else if( c.equals(Boolean.class) ){pc = boolean.class;}return pc;}}

    SpringHelper是我项目里实现的一个工具类,用于根据名字查找spring注入的实体对象。

    调用方式:

Scheduler.getInstance().call(obj, method, params);

    如果需要使用任务的执行结果,则可以这样:
...FutureTask<String> rs = Scheduler.getInstance().call(obj, method, params);//执行主线程的任务doSomething();... ...//获取任务结果,如果没有结果返回,则会阻塞等待返回rs.get();


1 0