Java,使用Future从线程返回值

标签 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();
    }

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

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

最佳答案

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

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

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

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);
}

关于Java,使用Future从线程返回值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45259681/

相关文章:

java - 什么是 JPA 实现?

C# 多线程 HttpWebRequest 超时.. 帮助!

c++ - 如何将位置返回为 x、y、z

javascript - 从函数返回并重新声明变量

java - 如何正确抛出 nullPointerException?

java - hibernate中子对象列表的条件查询

java - 特定数据的 SAXParser 失败

java - HashMap 与 ConcurrentHashMap : transfer between threads

c# - 在 C# 中,在继续处理 UI 更新的同时等待主线程? (.NET 2.0 CF)

Java:简单的递归问题