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];
}
}