Fork/Join并发框架
这个是笔者在看书的时候随手一记;
Fork/Join实现了ExecutorService接口的多线程处理器,可以把一个大任务划分若干的小任务
这里的运用场景是如果是大批量处理运算逻辑的数组
这里有分俩种,一种是没有返回值的任务,一种是有返回值的任务
//没有返回值的任务样例
class RecursiveActionDemo extends RecursiveAction{
private static final int SPLIT_LENGTH = 2; //每次批量处理数据个数的阈值
private List<String> tasks ; //需要处理的数据
RecursiveActionDemo(List tasks){
this.tasks = tasks;
}
@Override
protected void compute() {
if(tasks.size() <= SPLIT_LENGTH){
//线程中对每一个数据都进行处理
tasks.stream().forEach(tasks ->{
//这里为具体的数据处理逻辑
System.out.println(Thread.currentThread().getName()+" process task:"+tasks);
});
}else {
//使用二分法将大任务分割成俩个小任务
int middle = tasks.size() / 2 ;
List<String> leftList = tasks.subList(0,middle);
List<String> rightList = tasks.subList(middle,tasks.size());
RecursiveActionDemo left = new RecursiveActionDemo(leftList);
RecursiveActionDemo right = new RecursiveActionDemo(rightList);
//并且执行俩个消任务
left.fork();
right.fork();
}
}
}
public class Test {
public static void main(String[] args) throws InterruptedException {
//1参加ForkJoinPool类型的线程池实例
ForkJoinPool forkJoinPool = new ForkJoinPool();
//2定义好要处理的数据
List<String> tasks = Stream.of("task1","task2","task3","task4","task5","task6","task7").collect(Collectors.toList());
//提交可以分解的无返回值的任务
forkJoinPool.submit(new RecursiveActionDemo(tasks));
//4。阻塞当前线程,直到ForkjoinPool中的所有任务都执行结束
forkJoinPool.awaitTermination(2, TimeUnit.SECONDS);
//5关闭线程池
forkJoinPool.shutdown();
}
}
//RecursiveTask 为ForkJoinTask的抽象子类,该类定义了一个有返回值的任务
class RecursiveTaskDemo extends RecursiveTask<List<String>>{
private static final int SPLIT_LENGTH = 2; //每次批量处理数据个数的阈值
private List<String> tasks ; //需要处理的数据
RecursiveTaskDemo(List tasks){
this.tasks = tasks;
}
@Override
protected List<String> compute() {
if(tasks.size() <= SPLIT_LENGTH){
List<String> ProcessResult = new ArrayList<>();
//线程中对每一个数据都进行处理
tasks.stream().forEach(tasks ->{
//这里为具体的数据处理逻辑
//并且将每个数据的处理结构都写入ProcessResult 集合中
ProcessResult.add(tasks+"; processresult:finish");
});
return ProcessResult;
}else {
//使用二分法将大任务分割成俩个小任务
int middle = tasks.size() / 2 ;
List<String> leftList = tasks.subList(0,middle);
List<String> rightList = tasks.subList(middle,tasks.size());
RecursiveTaskDemo left = new RecursiveTaskDemo(leftList);
RecursiveTaskDemo right = new RecursiveTaskDemo(rightList);
//并且执行俩个消任务
left.fork();
right.fork();
//将任务执行的任务结果合并后返回
List<String> join = left.join();
join.addAll(right.join());
return join;
}
}
}
public class Test {
public static void main(String[] args) throws InterruptedException, ExecutionException {
//1.定义forkJoinPool
ForkJoinPool forkJoinPool = new ForkJoinPool(2);
//2.定义带出来的数据
List<String> tasks = Stream.of("task1","task2","task3","task4","task5","task6","task7").collect(Collectors.toList());
//3.提交可分解的有返回值的RecursiveTaskDemo任务
Future<List<String>> future = forkJoinPool.submit(new RecursiveTaskDemo(tasks));
//4.自认为执行的结果汇总
List<String> result = future.get();
System.out.println(Thread.currentThread().getName()+" process task result: "+ StringUtils.join(result,","));
//5。关闭线程池
forkJoinPool.shutdown();
}
俩段代码可以看的出,任务拆分利用了Fork/Join框架
ForkJoinPool:ExecutorService的实现类,负责工作的线程管理,任务队列维护即整个任务调度的流程控制,提供三种外部提交任务的方法:invoke(同步有返回值) ; execute(异步无返回值结果) ; submit(异步有返回结果,返回Future实现类,通过get获取结果);
这里提一嘴 工作线程有限处理队列中的任务(LIFO或者FIFO)顺序 这个顺序是取决于参数mode
FIFO:First Input First Output的缩写,先入先出队列,这是一种传统的按序执行方法,先进入的指令先完成并引退,跟着才执行第二条指令。
LIFO:后进先出法是指假定后入库的存货先发出,据此计算发出存货成本的方法。采用后进先出法时,每批发出存货的成本,按存货中最后入库的那批单价计算,如果发出存货的一批数量超过最后入库的那一批数量,超过部分依次按上一批入库的单价计算。