ForkJoinTask理解

3

subtask.fork()返回一个ForkJoinTask<Int>对象后会发生什么?之后compute()方法是如何被调用的?

我是Java的新手,正在尝试学习fork/join框架的概念。我在网上看到了下面的代码。我知道阅读Java API后,subtask.fork()返回一个ForkJoinTask<V>对象,这种情况下是一个ForkJoinTask<Int>。我不明白的是之后会发生什么?输出表明compute()方法在此之后被多次调用,但是是从哪里和如何调用的呢?

public class MyRecursiveAction extends RecursiveAction {

    public static void main(String[] args) {
        MyRecursiveAction mra1 = new MyRecursiveAction(100);
        ForkJoinPool fjp1 = new ForkJoinPool();
        fjp1.invoke(mra1);
    }

    private long workLoad = 0;

    public MyRecursiveAction(long workLoad) {
        this.workLoad = workLoad;
    }

    @Override
    protected void compute() {

        //if work is above threshold, break tasks up into smaller tasks
        if(this.workLoad > 16) {
            System.out.println("Splitting workLoad : " + this.workLoad);

            List<MyRecursiveAction> subtasks =
                new ArrayList<MyRecursiveAction>();

            subtasks.addAll(createSubtasks());

            for(RecursiveAction subtask : subtasks){
                subtask.fork();
            }

        } else {
            System.out.println("Doing workLoad myself: " + this.workLoad);
        }
    }

    private List<MyRecursiveAction> createSubtasks() {
        List<MyRecursiveAction> subtasks =
            new ArrayList<MyRecursiveAction>();

        MyRecursiveAction subtask1 = new MyRecursiveAction(this.workLoad / 2);
        MyRecursiveAction subtask2 = new MyRecursiveAction(this.workLoad / 2);

        subtasks.add(subtask1);
        subtasks.add(subtask2);

        return subtasks;
    }

}

输出:

Splitting workLoad : 100
Splitting workLoad : 50
Splitting workLoad : 50
Splitting workLoad : 25
Doing workLoad myself: 12
Doing workLoad myself: 12
Splitting workLoad : 25
Doing workLoad myself: 12
Doing workLoad myself: 12
Splitting workLoad : 25
Doing workLoad myself: 12
Splitting workLoad : 25
Doing workLoad myself: 12
Doing workLoad myself: 12
Doing workLoad myself: 12
1个回答

1

为了将工作分成两部分而不是手动执行它,您需要调用invokeAll,然后会创建2个新线程来“计算”结果,如果结果还不够小,则会再创建2个新线程等等。

您无法预测线程的执行顺序,因此每次运行此代码时消息的顺序都会有所变化。

public class MyRecursiveAction extends RecursiveAction {

    public static void main(String[] args) {
        MyRecursiveAction mra1 = new MyRecursiveAction(100);
        ForkJoinPool fjp1 = new ForkJoinPool();
        fjp1.invoke(mra1);
    }

    private long workLoad = 0;

    public MyRecursiveAction(long workLoad) {
        this.workLoad = workLoad;
    }

    @Override
    protected void compute() {

        //if work is above threshold, break tasks up into smaller tasks
        if(this.workLoad > 16) {
            System.out.println("Splitting workLoad : " + this.workLoad);

            invokeAll(new MyRecursiveAction(this.workLoad / 2), new MyRecursiveAction(this.workLoad / 2));

        } else {
            System.out.println("Doing workLoad myself: " + this.workLoad);
        }
    }

}

ForkJoinTask的Java文档


非常感谢您的帮助,真的非常感激。但是我还有一个问题,希望您能帮我解答。在invokeAll(new MyRecursiveAction(this.workload / 2), new MyRecursiveAction(this.workload / 2))之后,每个新创建的MyRecursiveAction对象会立即再次调用MyRecursiveAction.compute()方法吗?这样理解是否正确? - Thor
1
不是立即执行,它将取决于他们的线程何时处于活动状态,但是 compute 将被调用。 - Benoit Vanalderweireldt

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接