这是我参与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;
}