java 多线程 线程池:多核CPU利用ExecutorService newWorkStealingPool; ForkJoinPool线程池 执行可拆分的任务RecursiveAction;RecursiveTask

1,给定并行级别:

  • 1,ExecutorService newWorkStealingPool(int parallelism): 创建持有足够的线程的线程池来支持给定的并行级别,该方法还会使用多个队列来减少竞争
  • 2,ExecutorService newWorkStealingPool(): 该方法是前面方法的简化版本 如果前机器有4个CPU,则目标并行级别被设置为4
这两个方法是Java8新增的,这两个方法可充分利用多 CPU 并行的能力 这两个方法生成的 work stealing 池,都相于后台线程池,如果所有的前台线程都死亡了workstealing 池中的线程会自动死亡。
用法:
  1. 通过Executors.newWorkStealingPool()静态方法获取ExecutorService类对象
  2. 使用ExecutorService对象.submit(Runnable runnable)提交runnable 或Callable 接口类实现的任务对象
 示例代码:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @ClassName ExecutorsWorkStealingPoolTest
 * @projectName: object1
 * @author: Zhangmingda
 * @description: XXX
 * date: 2021/4/27.
 */
public class ExecutorsWorkStealingPoolTest {
    public static void main(String[] args) throws InterruptedException {
        Runnable r = () -> {
            String tName = Thread.currentThread().getName();
            try {
                System.out.println(tName + "开始运行");
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(tName + "运行结束");
        };
        /**
         * 创建支持多核CPU并行的线程池
         */
        ExecutorService executorService = Executors.newWorkStealingPool(); //译文:Stealing 窃取
        for (int i=0; i<10; i++){
            executorService.submit(r);
        }
        System.out.println(Runtime.getRuntime().availableProcessors()); //CPU核心数
        Thread.sleep(3000);
    }
}

 

 2、Java8 增强的 ForkJoinPool 用于拆分大的计算任务,拆分为多个小的计算任务

为了充分利用CPU、多核CPU的性能优势,计算机软件系统应该可以充分"挖掘"每个CPU的计算能力,绝不能让某个CPU处于"空闲"状态,为了充分利用多CPU、多核CPU的优势,可以考虑把一个任务拆分成多个"小任务",把多个"小任务"放到多个处理器核上并行执行;当多个"小任务"执行完成之后,再将这些执行结果合并起来即可。ForkJoinPool非常适合做密集计算型的任务

用法:

  1. 定义可以拆分的任务类,继承RecursiveAction类或RecursiveTask类(可以有返回值)实现其抽象方法compute;方法中自调用创建子任务对象.fork()方法提交拆分任务
  2. 用自定义任务类,实例化可拆分任务对象;子任务类的join()方法获取返回值
  3. 使用ForkJoinPool实例化对象,submit可拆分任务对象;返回ForkJoinTask对象
  4. ForkJoinPool对象awaitTermination执行任务(无返回值);
  5. 使用ForkJoinTask对象对象.get()方法获取返回值

无返回值示例代码(RecursiveAction类任务):

要求:给出一个int数据范围,范围内整数个数>100 则拆分不同的线程来打印。每个线程只打印不超过100个整数。

import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveAction;
import java.util.concurrent.TimeUnit;

/**
 * @ClassName MyRecursiveAction
 * @projectName: object1
 * @author: Zhangmingda
 * @description: XXX
 * date: 2021/4/27.
 */
public class MyRecursiveAction {
    /**
     * 定义一个支持拆分计算的任务
     */
    private static class PrintTaskRecursiveAction extends RecursiveAction{
        private int start;
        private int end;
        private final int MAXNUM = 100;

        /**
         * 构造实例传入任务需要的参数
         */
        public PrintTaskRecursiveAction(int start, int end) {
            this.start = start;
            this.end = end;
        }

        /**
         * 具体执行计算的任务的抽象方法重写
         */
        @Override
        protected void compute() {
            String tName = Thread.currentThread().getName();
            if ((end - start) < MAXNUM){
                System.out.println(tName + "    start:" + start);
                System.out.println(tName + "    end:" + end);
            }else {
                int middle = (start + end) /2;
                /**
                 * 大任务拆分为两个小任务,
                 */
                PrintTaskRecursiveAction subTask1 = new PrintTaskRecursiveAction(start,middle);
                PrintTaskRecursiveAction subTask2 = new PrintTaskRecursiveAction(middle,end);
                //分别执行两个小任务
                subTask1.fork();subTask2.fork();
            }
        }
    }

    /**
     执行计算任务
     */
    public static void main(String[] args) throws InterruptedException {
        ForkJoinPool forkJoinPool = new ForkJoinPool();
        PrintTaskRecursiveAction printTask = new PrintTaskRecursiveAction(1,300);
        //线程池提交任务
        forkJoinPool.submit(printTask);
        forkJoinPool.awaitTermination(1, TimeUnit.SECONDS);
        //关闭提交接口
        forkJoinPool.shutdown();
    }
}

 

 有返回值示例代码(RecursiveTask类任务):

要求:计算1~100的和,每个线程计算不超过10个数的和。

 
import java.util.concurrent.*;

/**
 * @ClassName MyRecursiveAction
 * @projectName: object1
 * @author: Zhangmingda
 * @description: XXX
 * date: 2021/4/27.
 */
public class ForkJoinPoolRecursiveTasksReturnExample {
    /**
     * 定义一个支持拆分计算的任务
     */
    private static class CalcNumCountTaskRecursiveTask extends RecursiveTask<Integer> {
        private int start;
        private int end;
        private final int MAXNUM = 30;

        /**
         * 构造实例传入任务需要的参数
         */
        public CalcNumCountTaskRecursiveTask(int start, int end) {
            this.start = start;
            this.end = end;
        }

        /**
         * 具体执行计算的任务的抽象方法重写
         */
        @Override
        protected Integer compute() {
            String tName = Thread.currentThread().getName();
            Integer count = 0;
            if ((end - start) < MAXNUM){
                System.out.println("start:" + start);
                System.out.println("end:" + end);
                for (int i=start; i<end; i++){
                    count+=i;
                }
                return count;
            }else {
                int middle = (start + end) /2;
                /**
                 * 大任务拆分为两个小任务,
                 */
                CalcNumCountTaskRecursiveTask subTask1 = new CalcNumCountTaskRecursiveTask(start,middle);
                CalcNumCountTaskRecursiveTask subTask2 = new CalcNumCountTaskRecursiveTask(middle,end);
                //分别执行两个小任务
                subTask1.fork();subTask2.fork();
                return subTask1.join() + subTask2.join();
            }
        }
    }

    /**
     执行计算任务
     */
    public static void main(String[] args) throws InterruptedException, ExecutionException {
        ForkJoinPool forkJoinPool = new ForkJoinPool();
        CalcNumCountTaskRecursiveTask calcCountTask = new CalcNumCountTaskRecursiveTask(1,101);
        //线程池提交任务
        ForkJoinTask<Integer> forkJoinTask =  forkJoinPool.submit(calcCountTask);
        //获取执行结果
        System.out.println(forkJoinTask.get());;
        //关闭提交接口
        forkJoinPool.shutdown();
    }
}

 

 

posted on 2021-04-27 18:17  zhangmingda  阅读(1178)  评论(0编辑  收藏  举报

导航