Java,使用Future从线程返回值

时间:2017-07-22 22:10:14

标签: java multithreading return

假设以下说明性示例。 B类涉及一些数值程序,例如阶乘。计算在一个单独的线程中运行:

public class B implements Callable <Integer> {
    private int n;

    public B(int n_) {n = n_;}

    public Integer call()  {return f();}

    public Integer f() {
            if (n == 1)  return 1;
            else {
                    int fn = 1;
                    for (int i = n; i > 1; i--) fn *= i;
                    return fn;
            }
    }
}

下一个A类使用阶乘来评估余数r = x ^ n / n!

public class A {

    public double rem (double x, int n){
            B b = new B(n);
            ExecutorService es = Executors.newFixedThreadPool(5);
            Future <Integer> nf = es.submit(b);  //Factorial
            es.submit(()->
            {          
                    double r = 1;     //Remainder x^n/n     
                    for (int i = 1; i <= n; i++) r = r * x;
                    try { r = r / nf.get();}
                    catch (Exception e) {e.printStackTrace();}                 
                    return r;
            });                     
            return 0;
    }
}

如何确保rem()函数在submit()过程完成后返回值?不幸的是,这不起作用:

    public static void main(String[] args) {
            A a = new A();
            double r = a.rem(0.5, 10);
    }

是否有必要在另一个线程中运行A并修改A以便:

public class A implements Callable <Double> {
    private int n;
    private double x;
    public A(double x_, int n_) {x = x_; n = n_;}
    public Double call()  {return rem(x, n);}
    ....
 }

并在一个单独的线程中运行A.rem()?

    public static void main(String[] args) {
            A a = new A(0.5, 10);
            ExecutorService es = Executors.newFixedThreadPool(5);
            Future <Double> nf = es.submit(a);  //Factorial
            double r = nf.get();
    }

有没有更简单的解决方案避免两个不同的线程?

我可以要一个简短的示例代码吗?

感谢您的帮助......

2 个答案:

答案 0 :(得分:2)

在提交给线程池的任务中使用Future.get()是危险的:当前线程被阻止,无法运行其他任务。这可能导致线程饥饿 - 一种特定的死锁。

正确的方法是制作非循环图,其中每个节点都是CompletableFuture类型的异步函数调用,它只在计算完所有参数后运行。只使用在主线程上调用的Future.get()提取一般结果。

这是一个这样的图表的示例,接近您想要实现的内容:首先,函数factorial和power并行运行。一旦它们都完成,就会调用计算提醒函数。

public static long fact(int n) {
    long res = 1;
    for (int i = n; i > 1; i--) res *= i;
    return res;
}

public static double pow(double base, int pow) {
    double r = 1;
    for (int i = 0; i < pow; i++) r *= base;
    return r;
}

public static double rem(double val1, long val2) {
    return val1/val2;
}

public static void main(String[] args) throws ExecutionException, InterruptedException {
    ExecutorService es = Executors.newFixedThreadPool(5);
    double base = 0.5;
    int n = 10;
    CompletableFuture<Double> f1 = CompletableFuture.supplyAsync(() -> pow(base, n), es);
    CompletableFuture<Long> f2 = CompletableFuture.supplyAsync(() -> fact(n), es);
    CompletableFuture<Double> f3 = f1.thenCombineAsync(f2, (v1,v2)->rem(v1,v2), es);
    double r1 = f3.get();
    System.out.println("r1="+r1);
    // compare with the result of synchronous execution:
    double r2 = rem(pow(base, n), fact(n));
    System.out.println("r2="+r2);
}

答案 1 :(得分:0)

可调用对象实现方法get,返回线程计算的值 - 看看以下链接: https://blogs.oracle.com/corejavatechtips/using-callable-to-return-results-from-runnables 欢呼声,

大卫