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

  • 相关阅读:
    VTIL & NoVmp 源码简要分析
    无需 Root 使用 IDA 调试 Android Native
    QWB 2021 StandOnTheGaints Writeup
    外部调用可执行文件中的函数
    CISCN 2021 西南赛区 Fix Writeup
    CISCN 2021 西南赛区 Reverse Writeup
    AES Block Cipher Implementation in C
    MTCTF 2021 Inject Writeup
    【题解】电子科技大学第十九届 ACM 程序设计竞赛
    洛谷P2596 [ZJOI2006]书架
  • 原文地址:https://www.cnblogs.com/zhangmingda/p/14710284.html
Copyright © 2020-2023  润新知