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(); } }