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

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

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

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

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 block
			logger.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();


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值