加入简单的程序示例 - 需要有关错误的指导

时间:2015-05-21 17:41:26

标签: java multithreading

我根据我对java中ForkJoinPool执行器服务的理解编写了一个小程序。程序的输出不符合要求。

我的理解: - 我对ForkJoinPool的理解是,它是另一种带有工作窃取功能的执行程序服务,它使一个线程从另一个队列中窃取工作,如果它完成了所有工作或已经空闲。这增加了线程对cpu的使用。 分叉用于将较大的任务分成较小的任务,直到任务足够简单以便顺序执行为止。 如果需要,连接将加入两个分开的任务以执行操作。

我的例子: - 基于上述理解,我尝试创建一个程序。任务是调用Parson对象的run方法。数组中有四个人对象。我希望四个线程​​在所有这些Person对象上并行工作,这意味着在一个包含四个对象的数组中,我的基本条件是数组,0,0。

预期输出: - Incompute(不确定多少次) 你好(4次) 线程ID(4次) 实际输出 - 在计算中多次打印并且没有任何时间打招呼。输出不是固定的,而是变化的。

有人可以指导我做出的错误吗?

package com.gc;

import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveAction;

public class FJMain {

public static void main(String[] args) {
    // TODO Auto-generated method stub

    Person p1 = new Person();
    Person p2 = new Person();
    Person p3 = new Person();
    Person p4 = new Person();

    Person[] array = new Person[4];
    array[0] = p1;
    array[1] = p2;
    array[2] = p3;
    array[3] = p4;

    FJMain.MyRecursiveAction action =  new FJMain().new MyRecursiveAction(array,0,3);

    ForkJoinPool pool = new ForkJoinPool(4);
    pool.invoke(action);

}

private class MyRecursiveAction extends RecursiveAction{

    private Person[] array;
    private int start;
    private int end;


    public MyRecursiveAction(Person[] array,int start,int end){
        this.array = array;
        this.start = start;
        this.end = end;
    }

    @Override
    protected void compute() {
        // TODO Auto-generated method stub
        System.out.println("In compute");
        int mid = (this.start + this.end)/ 2;
        if(mid < 1){
            computeDirectly(array,mid);
        }else{
            MyRecursiveAction subTask1 = new MyRecursiveAction(array, start, mid);
            subTask1.fork();
            MyRecursiveAction subTask2 = new MyRecursiveAction(array, mid + 1, end);
            subTask2.fork();
        }
    }

    private void computeDirectly(Person [] array,int end){
        for(Person p:array){
            p.name();
        }
    }

}

}


package com.gc;

public class Person {

public void name(){
    System.out.println("Hello");
    System.out.println(Thread.currentThread().getId());
}

}

修改

int beg = this.start;
        int last = this.end;
        int mid = (this.start + this.end)/ 2;
        if((last - beg) < 1){
            computeDirectly(array,beg);
        }else{
            MyRecursiveAction subTask1 = new MyRecursiveAction(array, start, mid);
            subTask1.fork();
            MyRecursiveAction subTask2 = new MyRecursiveAction(array, mid + 1, end);
            subTask2.fork();
        }

4 个答案:

答案 0 :(得分:0)

您的RecursiveAction会创建不会终止的递归任务。

new MyRecursiveAction(array, 0, 3);

创建

mid = (0 + 3) / 2 = 1
new MyRecursiveAction(array, 0, 1);
new MyRecursiveAction(array, 2, 3);

创建

mid = (0 + 1) / 2 = 0
completes

mid = (2 + 3) / 2 = 2
new MyRecursiveAction(array, 2, 2);
new MyRecursiveAction(array, 3, 3);

创建

mid = (2 + 2) / 2 = 2
new MyRecursiveAction(array, 2, 2);
new MyRecursiveAction(array, 3, 2);

mid = (3 + 3) / 2 = 3
new MyRecursiveAction(array, 3, 3);
new MyRecursiveAction(array, 4, 3);

令人作呕。其中一些将computeDirectly,但大多数不会因为它们退化。

你必须修复你的基础案例和你复发的方式。

答案 1 :(得分:0)

您的错误是打印“inCompute”。拿出来,程序运行正常。 System.out是共享的,你永远不知道打印的确切顺序。

F / J程序如何操作任务是该程序的内部。看看来源;这足以吓唬任何人。每次调用计算都会向system.out发送一个字符串,无论是拆分还是执行computeDirectly()。

<强> EDIT1:

此输出为Hello / n 12 / n四次。 12是线程ID,它是相同的。这告诉我,分裂线程正在从它自己的双端队列中获取新任务,并在其他线程有机会参与之前处理它们。由于你只使用四个数组,这是有道理的。

尝试使用400万的数组。 F / J并不意味着在这么小的输入上运行。并行化这么小的输入是没有意义的。

如果您没有得到相同的结果,那么您的环境还有另一个问题。

答案 2 :(得分:0)

您需要更好地学习如何调试程序。为什么不完成?你为什么不看到你想要的四个“你好”?你应该先去哪儿看看?

嗯,computeDirectly被击中了吗?不是,为什么?首先找出computeDirectly未被击中的原因。 mid的最小值是多少?如果您实际打印出值或调试了最小值mid,您可能会注意到1

如果您将computeDirectly的条件更改为

if (mid <= 1) {
     computeDirectly(array, mid);
}

您会看到预期的结果。

始终为1,因为0 + 3 / 2为1且无法进行任何分解。

答案 3 :(得分:0)

感谢所有回复。看起来在我的问题中编辑的基本条件看起来很好。我试图更改else条件并使用

中的代码

http://rashidnoorani.blogspot.in/2012/08/how-to-use-fork-join-framework-features.html

我仍然试图找出根本原因,可能需要一些时间。我会回复这篇文章。这是更改后的代码,我可以看到Hello被打印4次。

@Override
        protected void compute() {
            // TODO Auto-generated method stub
            int beg = this.start;
            int last = this.end;
            int mid = (this.start + this.end)/ 2;
            System.out.println(this.start +" " +mid + " "+this.end);

            if((last - beg) < 1){
                computeDirectly(array,beg);
            }else{
                /*MyRecursiveAction subTask1 = new MyRecursiveAction(array, start, mid);
                subTask1.fork();
                MyRecursiveAction subTask2 = new MyRecursiveAction(array, mid + 1, end);
                subTask2.fork();*/
                invokeAll(new MyRecursiveAction(array, start, mid), new MyRecursiveAction(array, mid + 1, end));
            }