Future模式
future模式是Java并发设计模式的一种,jdk内置了实现方式,可以直接拿过来用。当然也可以自己进行设计。这种模式实际上是把代码的执行从同步的方式改为了异步,当一个调用方法执行的时间比较长的时候,在原先单线程模式必须要等到该方法执行完成返回结果后在进行下一步的操作,如果这个操作是远程方法的调用,或者需要处理相当多的业务的时候,那么这个处理效率是非常低的,因此出现了future模式,当执行这种耗时比较久的方法时,向线程池提交一个任务,可以是单个的任务,也可以是一组任务。线程返回一个非真实数据的future对象,在这个时候可以利用这个时间去做其他的操作,操作完了之后再通过future对象去获取真实的结果,如果这个时候该任务还未返回结果,则方法阻塞,直到得到结果,也可以设置超时时间,这就是future的整个工作流程。
1. Future核心结构图
![图方便从《Java程序性能优化》一书上截取的](https://img-blog.csdn.net/20160118110641827)
其中,最重要的模块是FutureTask类,它实现了Runnable接口,作为单独的线程运行,再它的run方法中,通过Sync内部类,调用了Callable接口,并维护Callable接口的返回对象,当使用FutureTask.get()方法时,将结果返回,若无结果,则等待线程执行完成。
2.Future模式的用法
实现Callable接口,重写call方法 Callable接口是一个用户自定义的实现,在应用程序中,通过实现Callable接口的call方法,指定FutureTask的实际工作内容和返回对象。
Future接口提供的线程控制功能有:
![这里写图片描述](https://img-blog.csdn.net/20160118112340211)
class FutureTest implements Callable<String> {
@Override
public String call() throws Exception {
//复杂逻辑
return "result";
}
}
**#单个任务提交方式**
public static void main(String[] args) throws InterruptedException, ExecutionException {
ExecutorService service = Executors.newCachedThreadPool();
Future<String> result = service.submit(new FutureTest());
//其他业务逻辑
result.get();//获取真实结果
}
**#多个任务提交方法**
public static void main(String[] args) throws InterruptedException, ExecutionException {
ExecutorService service = Executors.newCachedThreadPool();
List<Callable<String>> callable = new ArrayList();
callable.add(new FutureTest());//可提交多个任务
//获取所有future对象
List<Future<String>> result = service.invokeAll(callable);
//其他业务逻辑
for (Future<String> future : result) {
future.get(); //获取所有结果
}
}
以上方法是jdk内置的实现的使用方式,看起来比较繁琐,必须要把复杂的逻辑放到Callable实现里面,每一个复杂的业务都要写一个实现,相对繁琐,很大程度上改变了原有的开发模式,重用起来比较难,维护起来也相对繁琐。
本人对其做了一个很简单的封装,提供一个代理类,再不改变原有开发模式的基础上通过反射方法进行调用。简化了原有的每个任务需要一个实现的繁琐方式。
以下是简单实现,欢迎提建议,修改
package com.qding.business.util;
import java.lang.reflect.Method;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import com.qding.util.GsonUtil;
import lombok.extern.log4j.Log4j;
/**
* @author ankang
*/
@Log4j
public class FutrueProxy{
private ExecutorService service;
public FutrueProxy(int nThreads){
if(nThreads > 0){
service = new ThreadPoolExecutor(nThreads, nThreads, 60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}else{
service = Executors.newCachedThreadPool();
}
}
/**
*
* @author ankang
* @param targerService 目标类
* @param targerMethod 目标方法名称 注:不要有方法名称一样,参数个数一样的本类认为重复的方法。
* @param resultType 返回值类型
* @param args 参数,与实际方法参数类型,顺序一致。
* @return 返回Future 通过get()获取真实返回值,此方法为阻塞方法
*/
public <T> Future<T> excute(final Object targerService, final String targerMethod, final Class<T> resultType, final Object...args) {
Future<T> real = service.submit(new Callable<T>() {
@Override
public T call() throws Exception {
try {
Method method = getMethod(targerService, targerMethod, args);
return (T)method.invoke(targerService, args);
} catch (Exception e) {
log.error(String.format("并行调用失败 targetService:[%s], targetMethod:[%s], args:[%s]",
targerService, targerMethod, GsonUtil.toJson(args)), e);
throw e;
}
}
});
return real;
}
/**
* @Description: 无返回值的并行调用
* @author: ankang
*/
public void excute(final Object targerService, final String targerMethod, final Object...args){
service.execute(new Runnable() {
@Override
public void run(){
try {
getMethod(targerService, targerMethod, args).invoke(targerService, args);
} catch (Exception e) {
log.error(String.format("并行调用失败 targetService:[%s], targetMethod:[%s], args:[%s]",targerService,
targerMethod, GsonUtil.toJson(args)), e);
}
}
});
}
private Method getMethod(Object targer, String targerMethod, Object...args){
if(args == null){
args = new Object[0];
}
int i = 0;
Method[] methods = targer.getClass().getMethods();
for (; i < methods.length; i++) {
if(targerMethod.equals(methods[i].getName())
&& args.length == methods[i].getParameterTypes().length){
break;
}
}
return methods[i];
}
}