一、將返回相同的多個任務轉換多線程操作方法
1、需求描述
a、對一個請求方法中存在的多個比較耗時的方法進行優化
b、當然,優化的角度很多如,SQL、緩存等,但今天着重說先多線程實現
c、轉換後的實現主要以匿名類的方式在方法中使用
2、具體實現
a、支持方法
package com.common.util.lock.executor;
import java.util.concurrent.Callable;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.Future;
/**
* 介紹
* 1、這裏使用ExecutorCompletionService儘快的獲取已完成任務
* 2、由於其原只接受固定數量的任務,下邊在提交時要使用到任務數量值
* 因此,需要擴展
*
* @return
*/
public class ExecutorCompletionExService<V> extends ExecutorCompletionService<V> {
private int taskNum = 0;
public ExecutorCompletionExService(Executor executor) {
super(executor);
}
@Override
public Future<V> submit(Callable<V> task){
taskNum++;
return super.submit(task);
}
public int getTaskNum() {
return taskNum;
}
}
b、操作方法
package com.common.util.lock.executor;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletionService;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public abstract class TaskExecutor<T> {
protected final Logger logger = LoggerFactory.getLogger(getClass());
private final ExecutorService pool;
public TaskExecutor(ExecutorService pool) {
this.pool = pool;
}
/**
* 獲取結果
* 1、目前尚不支持返回值爲基礎類型的情況
* 2、目前尚不支持泛型多於一層的校驗判斷,如Map<List<String>,String>
* 3、必須要進行泛型
* 4、目前還不支持預先指定返回集合泛型類型和實際返回集合泛型類型不一致問題
* 5、後期擴展,可以將放回的基礎類型放入Collection或map容器中
* @return
*/
public T getResult() {
try {
//此處使用擴展的類
ExecutorCompletionExService<T> cService = new ExecutorCompletionExService<T>(pool);
//將引用透出用於提交任務
submitTask(cService);
if(cService.getTaskNum()==0) {
return null;
}
//validate whether element generics or not
validateGenerics();
List<Object> objList = new ArrayList<Object>();
for(int i=0,size=cService.getTaskNum();i<size;i++) {
try {
Future<T> future = cService.take();
T result = future.get();
if(future.isDone()&&null!=result) {
objList.add(result);
}
if(future.isCancelled()) {
//will not be done!
logger.error("當前任務被取消!");
}
} catch (Exception e) {
logger.error("獲取跟蹤任務失敗!",e);
if(e.getCause() instanceof LoganException) {
LoganException loganEx = (LoganException) e.getCause();
throw loganEx;
}else {
throw new LoganException(ErrorMessageSystem.INNER_ERROR,"系統內部異常,請聯繫管理員!");
}
}
}
return merge(objList);
}finally {
//pool.shutdown();
}
}
private T merge(List<Object> objList){
if(CollectionUtils.isEmpty(objList)) {
return null;
}
Object obj = objList.get(0);
Class targetCls = null;
Type type = ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[0];
if(type.getClass().isAssignableFrom(Class.class)) {
targetCls = (Class) type;
}else {
targetCls = (Class)((ParameterizedType)type).getRawType();
}
//validate
validateSimpleType(targetCls,obj);
if(Map.class.isAssignableFrom(targetCls)) {
Map map = (Map) obj;
for(int i=1;i<objList.size();i++) {
map.putAll((Map) objList.get(i));
}
}else if(Collection.class.isAssignableFrom(targetCls)){
Collection collection = (Collection) obj;
for(int i=1;i<objList.size();i++) {
collection.addAll((Collection)objList.get(i));
}
}
return (null!=obj)?(T)obj:null;
}
private void validateSimpleType(Class cls,Object obj) {
if(obj.getClass().isPrimitive()||obj.getClass().equals(String.class)) {
throw new LoganException("不支持返回基礎類型!");
}
if(!cls.isAssignableFrom(obj.getClass())) {
throw new LoganException("指定類型和返回類型不一致!");
}
}
private void validateGenerics() {
Type type = this.getClass().getGenericSuperclass();
if(!ParameterizedType.class.isAssignableFrom(type.getClass())) {
throw new LoganException("實現類必須要進行泛型!");
}
Class targetCls = null;
if(type.getClass().isAssignableFrom(Class.class)) {
targetCls = (Class) type;
}else {
targetCls = (Class)((ParameterizedType)type).getRawType();
}
if(targetCls.isPrimitive()||targetCls.equals(String.class)) {
throw new LoganException("不支持返回基礎類型!");
}
}
protected abstract void submitTask(CompletionService<T> service);
}
c、調用方法
//用常量定義線程池
private final static ExecutorService pool = new ThreadPoolExecutor(CommonConstants.THREAD_POOL_CORE_SIZE, CommonConstants.THREAD_POOL_MAX_NUM_SIZE,
CommonConstants.THREAD_POOL_KEEP_ALIVE_TIME, CommonConstants.THREAD_POOL_UNIT,new LinkedBlockingQueue<Runnable>());
TaskExecutor<Map<String, String>> executor = new TaskExecutor<Map<String, String>>(pool) {
@Override
protected void submitTask(CompletionService<Map<String, String>> service) {
//提交第一個方法
service.submit(new Callable<Map<String, String>>() {
@Override
public Map<String, String> call() throws Exception {
return getWorkflowUsers(id,projectType);
}
});
//提交第二個方法
service.submit(new Callable<Map<String, String>>() {
@Override
public Map<String, String> call() throws Exception {
return relationEventUsers(id);
}
});
}
};
return executor.getResult();
二、將foreach操作轉多線程操作
1、需求分析
1、主要針對foreach中每次循環的內容都很耗時情況,將其修改成多線程
2、代碼實現
a、抽象方法
package com.common.util.lock.executor;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletionService;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.ObjectUtils;
/**
* 併發執行指定任務
* 1、共享同一個線程池
* 2、execut爲待實現執行方法,Object只能是集合類型
* 3、getResult獲取執行結果
* 4、T 是返回值類型,返回的是List<T>
* ----------------------------
* 適合執行相同性質的任務
* @author wb-zcf274530
*
* @param <T>
*/
public abstract class SynchroExecutor<T> {
protected final Logger logger = LoggerFactory.getLogger(getClass());
private final ExecutorService pool;
public SynchroExecutor(ExecutorService pool) {
this.pool = pool;
}
protected abstract T execute(Object obj);
public List<T> getResult(Object objList){
if(ObjectUtils.isEmpty(objList) || !(objList instanceof List)) {
return new ArrayList<T>();
}
List<Object> paramList = (List<Object>) objList;
CompletionService<T> cService = publicTask(paramList);
return getResult(cService,paramList.size());
}
private List<T> getResult(CompletionService<T> cService,int lenth){
try {
List<T> resultList = new ArrayList<T>();
for(int i=0,size=lenth;i<size;i++) {
try {
Future<T> future = cService.take();
T result = future.get();
if(future.isDone()&&null!=result) {
resultList.add(result);
}
if(future.isCancelled()) {
//will not be done!
logger.error("當前任務被取消!");
}
} catch (Exception e) {
logger.error("獲取跟蹤任務失敗!",e);
if(e.getCause() instanceof LoganException) {
LoganException loganEx = (LoganException) e.getCause();
throw loganEx;
}else {
throw new LoganException(ErrorMessageSystem.INNER_ERROR,"系統內部異常,請聯繫管理員!");
}
}
}
return resultList;
}finally {
//使用者不應該去關閉公用的線程池
//pool.shutdown();
}
}
private CompletionService<T> publicTask(List<Object> paramList){
CompletionService<T> cService = new ExecutorCompletionService<T>(pool);
for(Object param:paramList) {
cService.submit(new Callable<T>() {
@Override
public T call() throws Exception {
return execute(param);
}
});
}
return cService;
}
}
b、調用方法
//定義線程池,線程池可以爲多個service公用,不存在併發問題
private final static ExecutorService pool = new ThreadPoolExecutor(CommonConstants.THREAD_POOL_CORE_SIZE, CommonConstants.THREAD_POOL_MAX_NUM_SIZE,
CommonConstants.THREAD_POOL_KEEP_ALIVE_TIME, CommonConstants.THREAD_POOL_UNIT,new LinkedBlockingQueue<Runnable>());
SynchroExecutor<Vo> executor = new SynchroExecutor<Vo>(pool) {
@Override
protected Vo execute(Object obj) {
//循環體內操作內容
return Vo;
}
};
return executor.getResult(strategyVoList);
二、其他
1、阻塞方法最好設置時限
2、如上方法可以把線程池封裝到工具類內部,這樣就可以屏蔽時限細節。但對線程池線程的設置則要根據實際時效來設計。