【JUC-5】java多线程中的分治框架Fork/Join

news/2024/5/20 8:54:03 标签: java, 多线程, JUC, Fork/Join

ForkJoin

概念

Fork/Join是JDK 1.7加入的新的线程池实现,它体现的是一种分治思想,适用于能够进行任务拆分的cpu密集型运算

所谓的任务拆分,是将一个大任务拆分为算法上相同的小任务,直至不能拆分可以直接求解。使用ForkJoin框架需要将逻辑操作进行分治. 比较适合可以使用动态规划、回溯、递归等算法实现的逻辑。比如快速排序、二分查找,可以使用ForkJoin来提高运算能力。

Fork/Join在分治的基础上加入了多线程,可以把每个任务的分解和合并交给不同的线程来完成,进一步提升了运算效率

基本用法

  1. 定义任务类:创建一个继承自RecursiveTaskRecursiveAction的任务类。RecursiveTask用于有返回结果的任务,而RecursiveAction用于没有返回结果的任务。
  2. 实现compute()方法:在任务类中重写compute()方法,定义任务的具体计算逻辑。在该方法中,可以进行任务的拆分、执行以及结果的合并。
  3. 创建任务对象和ForkJoinPool:在主程序中,创建任务对象并将其提交给ForkJoinPool进行执行。

案例代码:

java">import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.concurrent.RecursiveTask;
import java.util.logging.Logger;

/**
 * 计算从begin到end的和
 */
public class MyRecursivelyTask extends RecursiveTask<Integer> {

    private static Logger log = Logger.getLogger("zzz");

    private Integer begin;
    private Integer end;

    public MyRecursivelyTask(Integer begin, Integer end) {
        this.begin = begin;
        this.end = end;
    }

    /**
     * 实现compute方法,拆分任务执行
     **/
    @Override
    protected Integer compute() {
		
        if (begin.equals(end)) {
            log.info("begin:"+ begin + "end:"+  end);
            return begin;
        }
        if (end - begin == 1) {
            log.info("begin:"+ begin + "end:"+  end);
            return begin + end;
        }

        Integer mid = (begin+end)/2;

        // 拆分任务
        MyRecursivelyTask t1 = new MyRecursivelyTask(mid + 1, end);
        MyRecursivelyTask t2 = new MyRecursivelyTask(begin, mid);

        log.info("t1:"+t1.toString());
        log.info("t2:"+t2.toString());
        
        // 执行拆分任务
        t1.fork();
        t2.fork();
		
        // 获取拆分的任务的结果
        Integer res1 = t1.join();
        Integer res2 = t2.join();

        return res1 + res2;
    }

    @Override
    public String toString() {
        return "MyRecursivelyTask{" +
                "begin=" + begin +
                ", end=" + end +
                '}';
    }
}

class forkJoinTest{
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        
		// 创建任务, 计算从1到5的和
        MyRecursivelyTask t = new MyRecursivelyTask(1, 5);
        // 创建fork/join线程池设置并行度为4
        ForkJoinPool pool = new ForkJoinPool(4);
        // 提交任务
        ForkJoinTask<Integer> res = pool.submit(t);
        // 获取任务结果
        System.out.println(res.get());
    }
}

ForkJoinPool中的API

  1. Future<T> submit(ForkJoinTask<T> task)
    • 提交一个ForkJoinTask任务进行执行,并返回一个Future对象,可通过该对象获取任务的执行结果。
  2. T invoke(ForkJoinTask<T> task)
    • 提交一个ForkJoinTask任务并立即执行,阻塞调用线程,直到任务完成并返回结果。
  3. void execute(ForkJoinTask<?> task)
    • 提交一个ForkJoinTask任务进行执行,但不返回任何结果。该方法不会阻塞调用线程。
  4. void shutdown()
    • 优雅地关闭ForkJoinPool,停止接受新任务,等待已提交的任务完成执行。
  5. List<Runnable> shutdownNow()
    • 立即关闭ForkJoinPool,试图中断正在执行的任务并返回所有未执行的任务列表。
  6. boolean awaitTermination(long timeout, TimeUnit unit)
    • 阻塞调用线程,等待指定的时间,直到所有任务完成执行或超时。
  7. int getPoolSize()
    • 获取当前ForkJoinPool中的工作线程数。
  8. int getActiveThreadCount()
    • 获取当前正在执行任务的工作线程数。
  9. int getParallelism()
    • 获取ForkJoinPool的并行度,即最大并行执行的线程数。
  10. long getStealCount()
    • 获取ForkJoinPool中的工作线程从其他工作线程中偷取任务的次数。
  11. long getQueuedTaskCount()
    • 获取当前在ForkJoinPool队列中等待执行的任务数。

http://www.niftyadmin.cn/n/1010433.html

相关文章

在idea中操作redis数据库(五种数据类型)

创建JedisTests测试类,为了避免重复重建和销毁Jedis对象,使用注解创建和销毁 Before After private Jedis jedis;Beforepublic void redisConnection(){jedis JedisPoolUtil.getJedis();}Afterpublic void redisClose(){jedis.close();} string类型 Test public void redisSt…

Python基础 —— 循环语句

如约来更新循环语句了.说到循环&#xff0c;有一定编程基础的小伙伴们都知道&#xff0c;我们最常用的循环莫过于 while循环&#xff0c;for循环和goto循环&#xff08;不过goto也不怎么常用&#xff09;&#xff0c;所以今天就来说一说 while循环和 for循环 来看一下本文大致…

自然语言处理从入门到应用——预训练模型总览:词嵌入的两大范式

分类目录&#xff1a;《自然语言处理从入门到应用》总目录 相关文章&#xff1a; 预训练模型总览&#xff1a;从宏观视角了解预训练模型 预训练模型总览&#xff1a;词嵌入的两大范式 预训练模型总览&#xff1a;两大任务类型 预训练模型总览&#xff1a;预训练模型的拓展 …

ElasticSearch - 根据经纬度,简单搜索指定距离范围内的数据

ES的地图检索方式 ES支持的地图检索方式有以下几种&#xff1b; geo_distance geo_bounding_box geo_polygon 1、geo_distance&#xff1a;直线距离检索&#xff0c;如给定点A&#xff0c;要求返回地图上距离点A三千米的商家&#xff08;点外卖场景&#xff09; 2、查找索引…

如何在Windows中批量创建多个文件夹

你需要更好地组织你的文件和文档吗&#xff1f;如果你在笔记本电脑或台式机上将相关文件分组到不同的文件夹中&#xff0c;那么总是很容易找到你需要的东西。你还可以更改图标的大小&#xff0c;使其在视觉上更美观。 在 Windows 中创建一个文件夹的传统做法是&#xff1a;右键…

vim多文件切换快捷键设置

1、基本切换指令 vim中在打开多个文件时&#xff0c;会有多个文件进行切换的需求。按:bn切换到下一个文件&#xff0c;按:bp切换到上一个文件。 2、快捷键设置 为了便捷操作&#xff0c;将切换命令设置成快捷键。 进入/home/yys个人目录下&#xff0c;vim .vimrc进入vimrc文…

安全中级11:sql注入+联合、报错、时间盲注+sqlmap使用

目录 一、sql注入原理 二、联合SQL注入的方法 1.总体的思路 &#xff08;1&#xff09;先进行闭合&#xff0c;进行报错 &#xff08;2&#xff09;进行逃逸 &#xff08;3&#xff09;外带数据 &#xff08;4&#xff09;获取库名 表名 列名 数据 &#xff08;5&#…

PL/SQL 中的数据导入和导出:CSV 文件格式详解

系列文章目录 文章目录 系列文章目录前言一、导出数据到 CSV 文件&#xff1a;二、导入 CSV 文件数据&#xff1a;总结 前言 在 PL/SQL 开发中&#xff0c;数据的导入和导出是常见的操作。本文将深入探讨如何使用 PL/SQL 导入和导出 CSV 文件格式的数据&#xff0c;帮助你轻松…