集合操作转多线程操作

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Q563573095/article/details/80807210

一、将返回相同的多个任务转换多线程操作方法
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、如上方法可以把线程池封装到工具类内部,这样就可以屏蔽时限细节。但对线程池线程的设置则要根据实际时效来设计。

猜你喜欢

转载自blog.csdn.net/Q563573095/article/details/80807210
今日推荐