等待ForkJoin Pool(Java)

时间:2016-12-22 05:51:35

标签: java multithreading threadpool cpu fork-join

我在java中使用Fork join pool进行多任务处理。现在我遇到了这样一种情况:对于每个任务,我需要点击一个url然后等待10分钟,然后再次点击另一个url来读取数据。现在问题是,对于那些10分钟,我的CPU处于空闲状态而没有启动另一个任务(超过fork join pool中定义的那些任务)。

static ForkJoinPool pool = new ForkJoinPool(10);
public static void main(String[] args){
    List<String> list = new ArrayList<>();
    for(int i=1; i<=100; i++){
        list.add("Str"+i);
    }
    final Tasker task = new Tasker(list);
    pool.invoke(task);

public class Tasker extends RecursiveAction{

    private static final long serialVersionUID = 1L;
    List<String> myList;
    public Tasker(List<String> checkersList) {
        super();
        this.myList = checkersList;
    }
    @Override
    protected void compute() {
        if(myList.size()==1){
            System.out.println(myList.get(0) + "start");
            //Date start = new Date();
            try {

                    Thread.sleep(10*60*1000);

            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            System.out.println(myList.get(0) + "Finished");
        }
        else{
            List<String> temp = new ArrayList<>();
            temp.add(  myList.get( myList.size()-1 )  );
            myList.remove( myList.size()-1 );

            Tasker left = new Tasker(myList);
            Tasker right = new Tasker(temp);

            left.fork();
            right.compute();
            left.join();
        }
    }

现在我该怎么办才能让CPU选择所有任务,然后等待它们。

2 个答案:

答案 0 :(得分:4)

不幸的是,ForkJoinPoolThread.sleep()面前效果不佳,因为它设计用于很快完成的许多短任务,而不是长时间阻止的任务。

相反,对于您要完成的任务,我建议您使用ScheduledThreadPoolExecutor并将您的任务分为两部分。

import java.util.*;
import java.util.concurrent.*;

public class Main {
    static ScheduledThreadPoolExecutor pool = new ScheduledThreadPoolExecutor(10);
    public static void main(String[] args){
        for(int i=1; i<=100; i++){
            pool.schedule(new FirstHalf("Str"+i), 0, TimeUnit.NANOSECONDS);
        }
    }
    static class FirstHalf implements Runnable {
        String name;
        public FirstHalf(String name) {
            this.name = name;
        }
        public void run() {
            System.out.println(name + "start");
            pool.schedule(new SecondHalf(name), 10, TimeUnit.MINUTES);
        }
    }
    static class SecondHalf implements Runnable {
        String name;
        public SecondHalf(String name) {
            this.name = name;
        }
        public void run() {
            System.out.println(name + "Finished");
        }
    }
}

如果Java提供了一个允许在Thread.sleep()期间释放底层资源(即参与线程池的内核线程)的线程池,那么你应该使用它,但我现在不知道一个

答案 1 :(得分:0)

根据docs forkJoin基本用法部分告诉:

  

if(我的工作部分足够小)     直接做这项工作   其他     把我的工作分成两部分     调用这两个部分并等待结果

希望如果您使用forkjoin

,这符合您的需求
public class Tasker extends RecursiveAction {
    static ForkJoinPool pool = new ForkJoinPool(10);
    static int threshold = 10;
    public static void main(String[] args){
        List<String> list = new ArrayList<>();
        for(int i=1; i<=100; i++){
           list.add("Str"+i);
        }
    final Tasker task = new Tasker(list);
    pool.invoke(task);
}


private static final long serialVersionUID = 1L;
List<String> myList;

public Tasker(List<String> checkersList) {
    super();
    this.myList = checkersList;
}

void computeDirectly() {
    for(String url : myList){
        System.out.println(url + " start");
    }
    //Date start = new Date();
    try {
        //keep hitting url
        while (true) {
            for(String url : myList) {
                //url hitting code here
                System.out.println(url + " hitting");
            }
            Thread.sleep(10 * 60 * 1000);
        }

    } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    for(String url : myList){
        System.out.println(url + " Finished");
    }
}

@Override
protected void compute() {
    if (myList.size() <= threshold) {
        computeDirectly();
        return;
    }

    //temp list have only one url
    //List<String> temp = new ArrayList<>();
    //temp.add(  myList.get( myList.size()-1 )  );
    //myList.remove( myList.size()-1 );


    //Tasker left = new Tasker(myList);
    //Tasker right = new Tasker(temp);


    //left.fork();
    //right.compute();
    //left.join();

    List<String> first = new ArrayList<>();
    List<String> second = new ArrayList<>();

    //divide list
    int len = myList.size();
    int smHalf = len / 2;//smaller half

    first = myList.subList(0, smHalf);
    second = myList.subList(smHalf + 1, len);

    invokeAll(new Tasker(first), new Tasker(second));

}

}