【问题标题】:Java Async is blocking?Java异步阻塞?
【发布时间】:2016-07-14 16:27:38
【问题描述】:

在Java上做了很多搜索之后,我真的很困惑以下问题:

  1. 为什么我要选择异步方法而不是多线程方法?

  2. Java futures 应该是非阻塞的。 非阻塞是什么意思?当从Future--即get()--提取信息的方法是阻塞的并且会简单地停止整个线程直到方法完成处理时,为什么称它为非阻塞?也许是一个回调方法,在处理完成时敲响完成的教堂钟声?

  3. 如何使方法异步?什么是方法签名?

    public List<T> databaseQuery(String Query, String[] args){
      String preparedQuery = QueryBaker(Query, args);
      List<int> listOfNumbers = DB_Exec(preparedQuery); // time taking task
      return listOfNumbers;
    }
    

    这种虚构的方法如何成为非阻塞方法?或者,如果您愿意,请提供一个简单的同步方法和它的异步方法版本。

【问题讨论】:

  • 一种选择是启动一个新线程来进行未来的解析,但这可能并不总是可行的。
  • dzone.com/articles/javautilconcurrentfuture Future 承诺在未来的某个时间返回结果(或重新抛出异常)。使用 isDone() 或 get(timeout) 轮询完成。在完成或向 executor worker 提交更多 Futures 之前,您可以做其他事情。如果您只需要一直同步一个单线程请求-响应,那么它可能更适合编写传统的东西。您需要创建 Callable 实例并将其提交给 executor worker。 Executor 给你一个 Future 承诺者。

标签: java multithreading asynchronous


【解决方案1】:

为什么我会选择异步方法而不是多线程方法?

异步方法允许您减少线程数。您可以发出一个异步调用,然后在它完成后收到通知,而不是在阻塞调用中绑定线程。这可以释放线程同时进行其他处理。

编写异步代码可能更复杂,但好处是提高了性能和内存利用率。

Java 期货应该是非阻塞的。非阻塞是什么意思?当从Future--即get()--提取信息的方法是阻塞的并且将简单地停止整个线程直到方法完成处理时,为什么将其称为非阻塞?也许是一个回调方法,在处理完成时敲响完成的教堂钟声?

查看CompletableFuture,它是在Java 8 中添加的。它比Future 有用得多。一方面,它允许您将各种回调和转换链接到期货。您可以设置将在未来完成后运行的代码。正如您所猜测的,这比阻止get() 呼叫要好得多。

例如,给定异步读写方法,如下所示:

CompletableFuture<ByteBuffer> read();
CompletableFuture<Integer> write(ByteBuffer bytes);

您可以像这样从文件中读取并写入套接字:

file.read()
    .thenCompose(bytes -> socket.write(bytes))
    .thenAccept(count -> log.write("Wrote {} bytes to socket.", count)
    .exceptionally(exception -> {
        log.error("Input/output error.", exception);
        return null;
    });

如何使方法异步?方法签名是什么?

你会让它返回一个未来。

public CompletableFuture<List<T>> databaseQuery(String Query, String[] args);

然后该方法负责在其他线程中执行工作并避免阻塞当前线程。有时你会准备好工作线程。如果没有,您可以使用ForkJoinPool,它使后台处理变得超级简单。

public CompletableFuture<List<T>> databaseQuery(String query, String[] args) {
    CompletableFuture<List<T>> future = new CompletableFuture<>();
    Executor executor = ForkJoinPool.commonPool();

    executor.execute(() -> {
        String preparedQuery = QueryBaker(Query, args);
        List<T> list = DB_Exec(preparedQuery); // time taking task
        future.complete(list);
    });
}

【讨论】:

    【解决方案2】:

    为什么我会选择异步方法而不是多线程方法

    对我来说它们听起来是一样的,除了异步听起来会在后台使用一个线程。

    Java 期货应该是非阻塞的?

    非阻塞操作通常使用 Future,但对象本身是阻塞的,尽管只有当你等待它时。

    非阻塞是什么意思?

    当前线程不等待/阻塞。

    当从 Future (即 get() )中提取信息的方法是阻塞时,为什么称它为非阻塞

    你称之为非阻塞。在后台启动操作是非阻塞的,但是如果你需要结果,阻塞是最简单的获得这个结果的方法。

    并且会简单地停止整个线程,直到方法完成处理?

    正确,它会这样做。

    也许是一个回调方法,在处理完成时敲响完成的教堂钟声?

    您可以使用 CompletedFuture,或者您可以在最后添加任何您想做的事情。您只需要阻止必须在当前线程中完成的事情。

    你需要返回一个Future,在等待的时候做点别的事情,否则使用非阻塞操作没有意义,你还不如在当前线程中执行,这样更简单更高效。

    你已经有了同步版本,异步版本看起来像

    public Future<List<T>> databaseQuery(String Query, String[] args) {
         return executor.submit(() -> {
             String preparedQuery = QueryBaker(Query, args);
             List<int> listOfNumbers = DB_Exec(preparedQuery); // time taking task
             return listOfNumbers;
         });
    }
    

    【讨论】:

      【解决方案3】:

      我不是多线程方面的专家,但为了我自己,我也会尝试回答这些问题

      为什么我会选择异步方法而不是多线程方法? (我的问题:我相信我读的太多,现在我自己很困惑)`


      多线程与多个线程一起工作,没有太多其他的东西。一个有趣的概念是,多个线程不能以真正的并行方式工作,因此将每个线程分成小块以产生并行工作的错觉。

      1

      多线程很有用的一个例子是实时多人游戏,其中每个线程对应于每个用户。用户 A 使用线程 A,用户 B 使用线程 B。每个线程可以跟踪每个用户的活动,并且可以在每个线程之间共享数据。

      2

      另一个例子是等待一个长的 http 调用。假设您正在设计一个移动应用程序,并且用户单击下载以获取 5 GB 的文件。如果您不使用多线程,用户将被卡在该页面上而无法执行任何操作,直到 http 调用完成。

      请务必注意,作为开发人员,多线程只是设计代码的一种方式。它增加了复杂性,并不总是必须完成。


      现在是异步与同步,阻塞与非阻塞

      这些是我从http://doc.akka.io/docs/akka/2.4.2/general/terminology.html找到的一些定义

      异步与同步

      如果调用者在方法返回值或抛出异常之前无法进行,则认为方法调用是同步的。另一方面,异步调用允许调用者在有限数量的步骤之后继续,并且方法的完成可以通过一些额外的机制发出信号(它可能是注册的回调、Future 或消息)。

      同步 API 可以使用阻塞来实现同步,但这不是必需的。一个 CPU 密集型任务可能会产生与阻塞类似的行为。一般来说,最好使用异步 API,因为它们可以保证系统能够继续运行。 Actor 本质上是异步的:Actor 可以在消息发送后继续进行,而无需等待实际传递发生。

      非阻塞与阻塞

      如果一个线程的延迟可以无限期地延迟其他一些线程,我们会谈论阻塞。一个很好的例子是可以由一个线程使用互斥独占使用的资源。如果一个线程无限期地持有该资源(例如意外运行一个无限循环),其他等待该资源的线程将无法继续。相反,非阻塞意味着没有线程能够无限期地延迟其他线程。

      非阻塞操作比阻塞操作更受欢迎,因为当系统包含阻塞操作时,系统的整体进度无法得到保证。

      我发现异步与同步更多地是指调用的意图,而阻塞与非阻塞是指调用的结果。但是,通常异步与非阻塞相伴而同步与阻塞相伴并没有错。


      2> Java 期货应该是非阻塞的?非阻塞是什么意思?当从 Future (即 get() )中提取信息的方法是阻塞的并且将简单地停止整个线程直到方法完成处理时,为什么将其称为非阻塞?也许是一个回调方法,在处理完成时敲响完成的教堂钟声?

      非阻塞不会阻塞调用该方法的线程。

      在 Java 中引入了期货来表示调用的结果,尽管它可能还不完整。回到http文件的例子,假设你调用了如下的方法

      Future<BigData> future = server.getBigFile(); // getBigFile would be an asynchronous method
      System.out.println("This line prints immediately");
      

      getBigFile 方法将立即返回并继续执行下一行代码。您稍后将能够检索未来的内容(或被通知内容已准备好)。 Netty、AKKA、Play 等库/框架广泛使用 Futures。

      如何使方法异步?方法签名是什么?

      我会说这取决于你想做什么。

      如果你想快速构建一些东西,你会使用 Futures、Actor 模型等高级函数,这些函数可以让你在多线程环境中高效地编程而不会犯太多错误。

      另一方面,如果您只是想学习,我会说最好从使用互斥锁、信号量等的低级多线程编程开始。

      如果您只是使用我编写的任何关键字搜索 java 异步示例,那么在 google 中此类代码示例很多。 如果您有任何其他问题,请告诉我!

      【讨论】:

      • 在那个多人游戏的例子中,数据共享不会造成竞争条件或数据不一致吗?
      • 这就是为什么数据结构是否是线程安全的变得很重要的原因。线程安全的数据结构可以从多个线程...安全地访问。此外,如果太多线程访问同一资源,这可能是性能不佳的原因=(
      猜你喜欢
      • 2020-11-12
      • 2018-04-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-10-28
      • 2016-02-15
      • 2018-12-31
      • 1970-01-01
      相关资源
      最近更新 更多