代码之家  ›  专栏  ›  技术社区  ›  Mohideen Imran Khan

理解Java可完成未来的行为[关闭]

  •  2
  • Mohideen Imran Khan  · 技术社区  · 7 年前

    我正在学习Java,我有一个比较简单的Java程序,它从API端点获取数据,看起来像这样:

    public class Main {
    
      public static String getJSON(String u) {
        if (u == null) throw new IllegalArgumentException("URL is null.");
        try {
          URL url = new URL(u);
          URLConnection site = url.openConnection();
          InputStream is = site.getInputStream();
          Scanner scanner = new Scanner(
                  new BufferedInputStream(is),
                  "UTF-8");
          String resp = "";
          while (scanner.hasNextLine()) {
            resp = resp + scanner.nextLine();
          }
          return resp;
        } catch (Exception e) {
          System.out.println(e);
          return null;
        }
      }
    
      public static void main(String[] args) {
        CompletableFuture<String> cf = CompletableFuture.supplyAsync(() ->
          getJSON("https://jsonplaceholder.typicode.com/posts/1")
        );
        cf.thenAcceptAsync(System.out::println);
        // System.out.println(cf.join()); <=== Commenting out this line
      }
    
    }
    

    我希望上面的代码可以打印出原始的JSON,但实际上它什么也不做。但是,如果我包括上面注释掉的行,代码就可以工作,但是它会两次打印出原始JSON。

    我的猜测是程序在 thenAcceptAsync 有机会完成,而不是在拦网时 .join() 包括功能。我的猜测是对的,如果是,我如何解决这个问题?

    2 回复  |  直到 7 年前
        1
  •  3
  •   ernest_k Petronella    7 年前

    您的主线程没有等待服务调用完成。您应该在completeTableFuture上调用join以等待其执行完成:

    cf.thenAcceptAsync(System.out::println).join();
    

    您可以使用以下修改后的代码版本来检查行为(只需在VM退出时添加一个关闭挂钩来打印文本):

    Runtime.getRuntime().addShutdownHook(new Thread(() -> System.out.println("Shutting down")));
    
    CompletableFuture<String> cf = CompletableFuture.supplyAsync(() -> {
        System.out.println("running...");
        String result = getJSON("https://jsonplaceholder.typicode.com/posts/1");
        System.out.println("Completed service call");
        return result;
    });
    cf.thenAcceptAsync(System.out::println).join();
    

    运行上述代码时,将输出以下代码:

    running...
    Completed service call
    {  "result json here"}
    Shutting down
    

    但是,没有 .join() ,立即显示以下输出: e 正在运行… 正在关闭

    简而言之, thenAcceptAsync(System.out::println) 在这种情况下,在HTTP调用完成之前,立即返回并完成主线程。如果在那之后你还有工作要做,它希望:

    cf = cf.thenAcceptAsync(System.out::println);
    doSomethingElse();
    doYetAnotherThing();
    cf.join()
    

    join 最终应该被调用,以防止VM过早终止,或者在必要时等待结果就绪。

        2
  •  1
  •   user9639236    7 年前
    import java.io.BufferedInputStream;
    import java.io.InputStream;
    import java.net.URL;
    import java.net.URLConnection;
    import java.util.Scanner;
    import java.util.concurrent.CompletableFuture;
    
    public class Main {
    
      public static String getJSON(String u) {
        if (u == null) throw new IllegalArgumentException("URL is null.");
        try {
          URL url = new URL(u);
          URLConnection site = url.openConnection();
          InputStream is = site.getInputStream();
          Scanner scanner = new Scanner(
                  new BufferedInputStream(is),
                  "UTF-8");
          String resp = "";
          while (scanner.hasNextLine()) {
            resp = resp + scanner.nextLine();
          }
          return resp;
        } catch (Exception e) {
          System.out.println(e);
          return null;
        }
      }
    
      public static void main(String[] args) {
        CompletableFuture<String> cf = CompletableFuture.supplyAsync(() ->
          getJSON("https://jsonplaceholder.typicode.com/posts/1")
        );
        //cf.thenAcceptAsync(System.out::println);
         System.out.println(cf.join()); 
      }
    
    }
    

    只需注释并在下面一行打开它将只打印一行