线程并发处理框架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 {

    /**
     * 需要分而治之的数组
     */
    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

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

 

你可能感兴趣的:(并发学习)