package com.cdkj.project.syn.common;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.Future;
import java.util.concurrent.RecursiveAction;
import java.util.concurrent.TimeUnit;
/**
* @author YUFEI
* @ClassName PrintTask3
* @description: TODO
* @date 2023年05月18日
* @version: 1.0
*/
public class PrintTask3 extends RecursiveAction {
// 个“小任务”最多只打印50个数
private static final int THRESHOLD = 50;
private int start;
private int end;
// 打印从 start 到 end 的任务
private List<String> list;
public PrintTask3(int start,int end,List<String> list) {
this.start = start;
this.end = end;
this.list = list;
}
//@SuppressWarnings("hiding")
@Override
protected void compute() {
//Integer rest = 100;
List<String> listString = new ArrayList<>();
//int i2=0;
// 当 end 与 start 之间的差小于 THRESHOLD 时,开始打印
if (end - start < THRESHOLD) {
// 业务逻辑写在这个 for 循环中
// 1000个任务,每批50个线程执行,总共需要分成20批,每批都会暂停5毫秒。
// 执行完一批再执行下一批。每一批都是50个线程同时执行,如果每个操作执行要
// 2秒,50个线程同时执行只有大概2秒可以执行完50操作,如果不用线程池串行执行,完成这50个操作就需要
// 需要100秒。
for (int i = start; i<end; i++) {
listString.add(list.get(i));
System.out.println(Thread.currentThread().getName()
+ "的 i 值:" + i);
System.out.println("输出批次:" + i);
//System.out.println("list.get("+i+"):" + list.get(i));
// 注意:不能在 for 循环中输出了子结果,如果有了这输出语句,就会只输出第一批执行的结果,
// 后面的结果无法再输出
//System.out.println("list.get("+i+"):" + listString.get(i));
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
// 注意:每执行完一批就把这批的计算结果存储到LIST中,是要1000个操作全部完成了才会统一取出结果。
// ,使用 使用 left.compute() 和right.compute() 方法复用当前线程,变成单线程执行在
// 这里是单线程执行任务,所以结果是顺序输出.
// 使用 left.fork() 和 right.fork() 方法是多线程执行任务,所以输出结果是乱序的
/*for (String string : listString) {
System.out.println(Thread.currentThread().getName());
System.out.println("计算结果:" + string);
}*/
} else {
// 当 end 与 start 之间的差大于 THRESHOLD,即要打印数超过 50 个时
// 将大任务分解成两个“小任务”
int middle = (start + end) / 2;
PrintTask3 left = new PrintTask3(start, middle,list);
PrintTask3 right = new PrintTask3(middle, end,list);
// 并行执行两个 "小任务"
left.fork();
right.fork();
//使用 compute 方法复用当前线程,变成单线程执行,有并行变成了串行效率低
//left.compute();
//right.compute();
/*int n = 0;
for (String string : listString) {
//System.out.println("n= " + n);
System.out.println("计算结果:" + string);
//n++;
}*/
}
// 注意:每执行完一批就把这批的计算结果存储到LIST中,是要1000个操作全部完成了才会统一取出结果。
// ,使用 使用 left.compute() 和right.compute() 方法复用当前线程,变成单线程执行在
// 这里是单线程执行任务,所以结果是顺序输出.
// 使用 left.fork() 和 right.fork() 方法是多线程执行任务,所以输出结果是乱序的
for (String string : listString) {
System.out.println(Thread.currentThread().getName());
System.out.println("计算结果:" + string);
}
}
}
class ForkJoinPoolTest3 {
public static void main(String[] args) throws Exception {
ForkJoinPool pool = new ForkJoinPool();
List<String> list2 = new ArrayList<>();
for (int i = 0; i < 1000; i++) {
list2.add("test"+i);
}
// 提交可分解的 PrintTask 任务
pool.submit(new PrintTask3(0, 1000,list2));
//线程阻塞100秒,等待所有任务完成。如果100秒还有任务没执行完成,线程池会关闭,退出任务,
//就会导致部分任务没完成。所以这个线程池阻塞时间必须大于线程池完成所有任务的时间
pool.awaitTermination(100, TimeUnit.SECONDS);
System.out.println("输出完成");
// 关闭线程池
pool.shutdown();
}
}
