【问题标题】:Java asynchronously call a method for target outputJava异步调用目标输出的方法
【发布时间】:2020-06-09 23:00:50
【问题描述】:

假设我有一个名为check 的阻塞方法,如下所示:

boolean check(String input) {}

这将对输入进行一些检查并返回决定。

现在我想对输入列表异步运行此检查,并且我想在其中一个输入通过检查后立即返回主线程,因此我不必等待所有异步调用完全的。等待所有线程完成的唯一一种情况是没有输入通过检查。使用输入列表异步运行该方法很简单,但我不确定在获得通过检查的输入的目标输出后如何返回主线程。

【问题讨论】:

  • 有趣的问题。能否提供一个可行的检查功能?

标签: java asynchronous


【解决方案1】:

这是一个非常简单的工作示例,可以实现您的要求

Future<Boolean> future = CompletableFuture.runAsync(() -> {
    // Do your checks, if true, just return this future
    System.out.println("I'll run in a separate thread than the main thread.");
});

// Now, you may want to block the main thread waiting for the result
while(!future.isDone()) {
    // Meanwhile, you can do others stuff
    System.out.println("Doing other stuff or simply waiting...");
}

// When future.isDone() returns, you will be able to retrieve the result
Boolean result = future.get();

【讨论】:

    【解决方案2】:

    一个基本的并行流就可以做到这一点:

    boolean match = inputs.parallelStream().anyMatch(input -> check(input));
    

    如果找到与check 匹配的某些输入,则以match==true 提前返回。 match 如果所有输入都被检查并且没有匹配,则为 false。

    在标准情况下,它将使用 fork/join 线程池。但是通过进一步的努力,您可以避免这种情况。

    【讨论】:

    • ParallelStream 上的操作仍处于阻塞状态,并将等待它产生的所有线程完成。这些线程是异步执行的(它们不会等待前一个线程完成),但这并不意味着您的整个代码开始异步运行。来源:here
    • 是的,调用anyMatch的线程被阻塞了。如果你不想那样。 Snix 方法是要走的路。当所有中间工作完成时,轮询未来(使用isDone())或阻塞(使用get())。您也可以同时使用两者。启动Future,在未来使用parallelStream(),使用多个线程检查输入。
    【解决方案3】:

    看看这个例子,看看它是否对你有帮助:

    package callrandom;
    
    import java.util.ArrayList;
    import java.util.List;
    import java.util.concurrent.ExecutionException;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Future;
    import java.util.concurrent.ThreadPoolExecutor;
    
    import static java.lang.System.exit;
    import static java.lang.System.out;
    import static java.util.concurrent.Executors.newFixedThreadPool;
    import static java.util.logging.Level.SEVERE;
    import static java.util.logging.Logger.getLogger;
    
    import static callrandom.Randomize.gotFive;
    
    public class CallRandom {
    
        public static void main(String[] args){
            int MAXTHREADS = 5;
            List<Future<Integer>> futs = new ArrayList<>();
    
            ExecutorService executor = newFixedThreadPool(MAXTHREADS);
            ThreadPoolExecutor pool = (ThreadPoolExecutor) executor;
    
            for (int x = 0; x < MAXTHREADS; x++) {
                out.println("Run instance: " + x);
                futs.add(executor.submit(new Randomize()));
            }
    
            do {
            } while (!gotFive);
    
            for (int x = 0; x < MAXTHREADS; x++) {
                if (futs.get(x).isDone()) {
                    try {
                        out.println("Return from thread: " + x + " = " + futs.get(x).get());
                    } catch (InterruptedException | ExecutionException ex) {
                        getLogger(CallRandom.class.getName()).log(SEVERE, null, ex);
                        throw new RuntimeException(ex);
                    }
                }
                out.println("Cancel instance: " + x + " = " + futs.get(x).cancel(true));
            }
            exit(0);
        }
    }
    

    ...和线程:

    package callrandom;
    
    import static java.lang.System.in;
    import static java.lang.System.out;
    import static java.lang.Thread.currentThread;
    import java.util.Scanner;
    import java.util.concurrent.Callable;
    
    public class Randomize implements Callable<Integer> {
    
        public static volatile Boolean gotFive = false;
    
        @Override
        public Integer call() throws Exception {
            return findNumber();
        }
    
        private Integer findNumber() throws InterruptedException {
            int number = 0;
            do {
                Scanner sc = new Scanner(in);
                out.println(currentThread().getName() + ": Insert a number [5 stops this threads and triggers main thread to interrupt all others]:");
                number = sc.nextInt();
            } while (number != 5 && !gotFive);
            gotNumber();
            return number;
        }
    
        public synchronized void gotNumber() {
            out.println(currentThread().getName() + " got a 5!");
            gotFive = true;
        }
    }
    

    您有 5 个线程正在运行并等待输入。他们一直要求输入,直到您在其中任何一个中输入数字 5。该线程返回主线程,主线程取消所有剩余线程。您可能必须完成一个循环,这意味着在每个线程中插入至少 1 个数字,以便线程确认中断请求并自行取消,尽管有时它会在未完成循环的情况下自行取消。

    如果这是我第一次使用 Callable 和 Future,肯定会感谢对这个示例的批判性评价。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-04-29
      • 1970-01-01
      • 2019-08-10
      • 1970-01-01
      • 2010-12-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多