线程并发处理框架ForkJoin

ForkJoin:分而治之、工作窍取

分而治之:字面理解就是将一个任务分开治理,当一个任务达到某个需要分开治理的条件时,将该任务分成不同的小任务进行执行,最后汇总。

采用RecursiveTask进行同步执行任务并返回一个数组和

package com.example.demo.concurrentlearn.forkjoin;

import java.util.Random;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveTask;

/**
 * @author wml
 * 计算一个Integer数组的和
 */
public class ForkJoinJob extends RecursiveTask<Integer> {

    /**
     * 需要分而治之的数组
     */
    private Integer[] integers;
    /**
     * 任务的开始下标
     */
    private Integer begin;
    /**
     * 任务的结束下标
     */
    private Integer end;
    /**
     * 数组超过多大就分而治之
      */
    private Integer threshold = 5000;

    public ForkJoinJob(Integer[] integers, Integer begin, Integer end) {
        this.integers = integers;
        this.begin = begin;
        this.end = end;
    }

    @Override
    protected Integer compute() {

        if(end - begin < threshold){
            // 如果数组长度小于阈值,开始计算累加
            Integer integer = 0;
            for(int i=begin;i<=end;i++){
                integer += integers[i];
            }
            return integer;
        }
        // 数组长度大于阈值,开始分而治之 将一个数组平均破开分成2个数组长度相等的数组
        // 数字越大计算越久,这个在forkJoin中存在工作窍取,先工作完的线程会分摊还在工作线程的任务
        // 基本不会出现分配不均导致资源空闲的问题
        Integer mid = (end + begin) / 2;
        ForkJoinJob forkJoin = new ForkJoinJob(integers, begin, mid);
        ForkJoinJob forkJoin1 = new ForkJoinJob(integers, mid + 1, end);
        // 执行2个任务
        invokeAll(forkJoin,forkJoin1);
        // 通过join方法获取结果数据
        Integer join = forkJoin.join();
        Integer join1 = forkJoin1.join();
        // 返回2个任务的累计和
        return join+join1;
    }

    /**
     * 获取一个数组
     * @param integer
     * @return
     */
    public static Integer[] getArr(Integer integer){

        Integer[] integers = new Integer[integer];

        for (int i=0;i<integers.length;i++){
            integers[i] = new Random().nextInt(integers.length*2);
        }
        return integers;
    }



    public static void main(String[] args) {
        // 类似于线程池,但是它具有工作窍取的特点,不会出现资源浪费的情况
        ForkJoinPool forkJoinPool = new ForkJoinPool();

        Integer[] arr = getArr(100000);

        long l = System.currentTimeMillis();
        ForkJoinJob forkJoinJob = new ForkJoinJob(arr, 0, arr.length - 1);
        // 将任务丢到池子里去执行
        Integer invoke = forkJoinPool.invoke(forkJoinJob);
        System.out.println("求和总数:"+invoke);
    }
}

采用RecursiveAction异步执行无返回值的任务(遍历某个文件夹下面的指定文件格式的文件)

package com.example.demo.concurrentlearn.forkjoinAyn;

import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveAction;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author wuml
 */
public class TestFile extends RecursiveAction {

    /**
     * 要遍历的文件(文件路径)
     */
    private File file;
    /**
     * 计算总共有多少个文件
     */
    AtomicInteger atomicInteger;

    public TestFile(File file,AtomicInteger atomicInteger) {
        this.file = file;
        this.atomicInteger = atomicInteger;
    }

    @Override
    protected void compute() {
        // 传入的主文件夹或文件夹
        File[] files = file.listFiles();
        // 当传入的是个文件夹时,将文件夹下的其他文件夹归入list,然后再去迭代
        List<TestFile> objects = new ArrayList<>();
        if(files!=null){
            for (File file:files){
                if(!file.isDirectory()){
                    // 如果是文件就打印文件地址
                    if(file.getAbsolutePath().endsWith("mp4")){
                        atomicInteger.incrementAndGet();
                        System.out.println("txt文件:"+file.getAbsolutePath());
                    }
                }else{
                    // 如果是文件夹的话 添加到文件夹的list中
                    objects.add(new TestFile(file,atomicInteger));
                }
            }
            if(!objects.isEmpty()){
                // 需要遍历的文件list不为空,继续迭代
                Collection<TestFile> testFiles = invokeAll(objects);
                for(TestFile testFile:testFiles){
                    testFile.join();
                }
            }
        }
    }


    public static void main(String[] args) throws InterruptedException {
        AtomicInteger atomicInteger = new AtomicInteger(0);
        File file = new File("D:/study");
        TestFile file1 = new TestFile(file,atomicInteger);
        ForkJoinPool forkJoinPool = new ForkJoinPool();
        forkJoinPool.execute(file1);

        System.out.println("-=============main线程在");
        // 模拟执行其他的主任务
        Thread.sleep(1);
        // 采用join加塞 防止main主线程执行结束,而future还未执行完
        file1.join();
        System.out.println("遍历完成"+atomicInteger.get());
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值