从工作线程将结果返回给调用方

时间:2019-04-17 16:06:01

标签: java multithreading

SO上有一些答案,但是我正在寻找使用我的代码的解决方案,以便清楚地理解。

我已经使用Executor创建了工作线程,执行工作后,工作人员会将结果返回给调用方(主要)

工人

public class Worker implements Runnable {

    private final int num;

    public Worker(int num) {
        this.num = num;
    }

    @Override
    public void run() {
        System.out.println("Starting job: " + num);
        try {
            Thread.sleep(2000);
            System.out.println("end job:" + num);

            String result = "result " + num; // how to pass all the results back to the caller

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

工人测试

public class WorkerTest {

    private static List<String> result = new ArrayList<>();

    public static void main(String[] args) {
        ExecutorService executorService = Executors.newFixedThreadPool(5);
        for (int i = 0; i < 10; i++) {
            Runnable worker = new Worker(i);
            executorService.execute(worker);
        }
        executorService.shutdown();
        while(!executorService.isTerminated());
    }
}

3 个答案:

答案 0 :(得分:1)

这是您的完整代码 公共类WorkerTest {     私有静态列表结果= new ArrayList <>();

public static void main(String[] args) throws Exception {
    Future[] futures = new Future[10];
    ExecutorService ex = Executors.newFixedThreadPool(5);
    for (int i = 0; i < 10; i++) {
        Callable worker = new Worker(i);

        futures[i] = ex.submit(worker);

    }
    for (int i = 0; i < 10; i++) {
        String resultString = (String) futures[i].get();
        System.out.println(resultString);
    }
    ex.shutdown();
    while (!ex.isTerminated());
}

}

class Worker implements Callable<String> {

private final int num;

public Worker(int num) {
    super();
    this.num = num;
}

@Override
public String call() throws Exception {
    String result = null;
    System.out.println("starting job " + num);
    try {
        Thread.sleep(2000);
        System.out.println("end job " + num);
        result = "result" + num;

    } catch (Exception e) {
        e.printStackTrace();
    }
    return result;
}

}

或者,如果您要将结果存储在列表中,也可以这样做。

public class ExecutorTest {
private static List<String> result = new ArrayList<>();

public static void main(String[] args) throws Exception {
    ExecutorService ex = Executors.newFixedThreadPool(5);
    for (int i = 0; i < 10; i++) {
        Callable worker = new Worker(i);

        Future<String> stringResult= ex.submit(worker);
        String output = stringResult.get();
        result.add(output);
        System.out.println(output);

    }
    ex.shutdown();
    while (!ex.isTerminated());
    System.out.println("All results received frmo executor service ");
    System.out.println(result);
}


}

答案 1 :(得分:0)

您应该实现Callable而不是实现Runnable,然后使用返回Future的方法

public class Worker implements Callable<String> {
  @Override
  public String call() {
    return "123";
  }
}


ExecutorService es = Executors.newFixedThreadPool(5);
Future<?> f = es.submit(new Worker());
String result = f.get(); // 123

答案 2 :(得分:0)

  

>我不能把头放在[未来]上。

也许幕后的一瞥会有所帮助

Future是一个接口,但是有一些标准的库类,implements Future是我们不知道的名称。假设它叫FutureImpl

FutureImpl实例具有一个由Future API指定的get()方法,并且它具有另一个我们看不到的方法,但我们将其称为put(x)

当Karol Dowbecki的示例代码将任务提交给执行者服务时,执行者服务将创建一个新的FutureImpl实例并对其执行以下两项操作:

  1. 它提供了对将要执行任务的工作线程的引用,并且
  2. 它从es.submit(...)调用中返回引用。

    Future<?> f = es.submit(...);
    

工作线程将调用您赋予它的任务函数,然后它将获取返回的值,并将其存储在FutureImpl对象中:

futureImpl.put(task.Call());
  

注意! ffutureImpl是同一对象的两个不同名称。唯一的区别是,工作线程知道它是FutureImpl类的实例,而主线程只知道它是implements Future类的某个实例。

无论如何,回到主线程...它可以在工作人员正在执行其工作时做其他事情,然后最终,主线程可以尝试检索该值:

String result = f.get();

如果任务已经完成,并且工作线程已经在主线程调用futureImpl.put(...)之前调用了f.get(),那么f.get()将立即返回该值。但是,如果主线程首先调用f.get(),那么get()调用将等待,直到辅助线程完成任务并存储值。