多线程并发工具类

158 阅读2分钟

这是我参与8月更文挑战的第6天,活动详情查看:8月更文挑战

使用方法

package com.example.concurrent;

import java.util.ArrayList;
import java.util.List;

/**
 * com.example.concurrent
 * Description:
 *
 * @author jack
 * @date 2021/7/6 10:39 上午
 */
public class Test {
    public static void main(String[] args) {
        List<Integer> numList = new ArrayList<>();
        for (int i = 1; i <= 10; i++) {
            numList.add(i);
        }
        ConcurrentResult<Integer> sum = ConcurrentUtils.runAsync(numList, Test::addNum, null, ResultType.SUM);
        System.out.println(sum);
    }

    private static Integer addNum(Integer num) {
        return num + num;
    }
}

package com.example.concurrent;

import com.example.concurrent.processor.ConcurrentResultProcessor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;

/**
 * com.example.concurrent
 * Description:
 *
 * @author jack
 * @date 2021/7/6 10:18 上午
 */
@Slf4j
public class ConcurrentUtils {

    /**
     * 一般IO型任务核心线程数为 Runtime.getRuntime().availableProcessors()*2
     */
    private static final int POOL_SIZE = Runtime.getRuntime().availableProcessors() * 2;
    /**
     * 最大线程池数
     */
    private static final int MAX_POOL_SIZE = Runtime.getRuntime().availableProcessors() * 2;
    /**
     * 最大等待时间(单位:毫秒)
     */
    private static final int MAX_WAIT_TIME = 200;
    /**
     * 接口平均RT(单位:毫秒)
     */
    private static final int AVG_RT = 20;
    /**
     * 任务队列大小
     */
    private static final int QUEUE_SIZE = POOL_SIZE * MAX_WAIT_TIME / AVG_RT;

    private static final ExecutorService EXECUTORS = new ThreadPoolExecutor(POOL_SIZE, MAX_POOL_SIZE, 0,
            TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(QUEUE_SIZE),
            new NamedThreadFactory("concurrent-executor", true), new ThreadPoolExecutor.CallerRunsPolicy());

    public static <T, R> ConcurrentResult<R> runAsync(List<T> parameterList, Function<T, R> function, ExecutorService executorService, ResultType mergeType) {
        if (CollectionUtils.isEmpty(parameterList)) {
            return null;
        }
        List<R> taskResult = new ArrayList<>(parameterList.size());
        List<Exception> exceptionList = new ArrayList<>();

        List<Future<R>> futureList = invoke(parameterList, function, executorService);
        futureList.forEach(f -> {
            try {
                taskResult.add(f.get());
            } catch (Exception e) {
                exceptionList.add(e);
                log.error("ConcurrentUtils#runAsync error parameter:{}", parameterList, e);
            }
        });

        ConcurrentResult<R> concurrentResult = new ConcurrentResult<>();
        ConcurrentResultProcessor<R> concurrentResultProcessor = ConcurrentResultProcessFactory.get(mergeType);
        if (concurrentResultProcessor == null) {
            return null;
        }
        concurrentResult.setR(concurrentResultProcessor.mergeResult(taskResult));
        concurrentResult.setExceptions(exceptionList);
        return concurrentResult;
    }

    private static <T, R> List<Future<R>> invoke(List<T> parameterList, Function<T, R> function, ExecutorService executorService) {
        List<Future<R>> futureList = new ArrayList<>(parameterList.size());
        ExecutorService executor = Objects.isNull(executorService) ? EXECUTORS : executorService;
        parameterList.forEach(parameter -> {
            Future<R> future = executor.submit(() -> function.apply(parameter));
            futureList.add(future);
        });
        return futureList;
    }

}


class NamedThreadFactory implements ThreadFactory {

    private final AtomicInteger mThreadNum = new AtomicInteger(1);
    private final String mPrefix;
    private final boolean mDaemon;
    private final ThreadGroup mGroup;

    public NamedThreadFactory(String prefix, boolean daemon) {
        mPrefix = prefix + "-thread-";
        mDaemon = daemon;
        SecurityManager s = System.getSecurityManager();
        mGroup = (s == null) ? Thread.currentThread().getThreadGroup() : s.getThreadGroup();
    }

    @SuppressWarnings("all")
    @Override
    public Thread newThread(Runnable runnable) {
        String name = mPrefix + mThreadNum.getAndIncrement();
        Thread ret = new Thread(mGroup, runnable, name, 0);
        ret.setDaemon(mDaemon);
        return ret;
    }
}

package com.example.concurrent;

import com.example.concurrent.processor.ConcurrentResultProcessor;
import com.example.concurrent.processor.ListResultProcessor;
import com.example.concurrent.processor.MapResultProcessor;
import com.example.concurrent.processor.SetResultProcessor;
import com.example.concurrent.processor.SumResultProcessor;

import java.util.HashMap;
import java.util.Map;

/**
 * com.example.concurrent
 * Description:
 *
 * @author jack
 * @date 2021/7/6 10:27 上午
 */
public class ConcurrentResultProcessFactory {

    private static final Map<ResultType, ConcurrentResultProcessor> CONCURRENT_RESULT_PROCESS_FACTORY = new HashMap<>();

    static {
        CONCURRENT_RESULT_PROCESS_FACTORY.put(ResultType.LIST, new ListResultProcessor<>());
        CONCURRENT_RESULT_PROCESS_FACTORY.put(ResultType.SET, new SetResultProcessor<>());
        CONCURRENT_RESULT_PROCESS_FACTORY.put(ResultType.MAP, new MapResultProcessor<>());
        CONCURRENT_RESULT_PROCESS_FACTORY.put(ResultType.SUM, new SumResultProcessor<>());
    }

    /**
     * 根据mergeType获取结果处理器实例
     *
     * @param mergeType 合并类型
     * @return 具体处理器
     */
    @SuppressWarnings("unchecked")
    static <T> ConcurrentResultProcessor<T> get(ResultType mergeType) {
        return CONCURRENT_RESULT_PROCESS_FACTORY.get(mergeType);
    }
}

package com.example.concurrent;

/**
 * com.example.concurrent
 * Description:
 *
 * @author jack
 * @date 2021/7/6 10:28 上午
 */
public enum ResultType {
    /**
     * 普通的List合并,不会去重
     */
    LIST,
    /**
     * Set集合
     */
    SET,
    /**
     * Map集合合并,key相同时直接覆盖(适用于相同key且value相同的场景)
     */
    MAP,
    /**
     * 求和(适用于进行批量插入对影响条数统计)
     */
    SUM,
}

package com.example.concurrent;

import lombok.Data;

import java.util.List;

/**
 * com.example.concurrent
 * Description:
 *
 * @author jack
 * @date 2021/7/6 10:30 上午
 */
@Data
public class ConcurrentResult<R> {
    /**
     * 返回结果
     */
    private R r;
    /**
     * 任务执行时的异常信息
     */
    private List<Exception> exceptions;
}