Java Async是否阻塞?

时间:2016-03-27 07:34:35

标签: java multithreading asynchronous

在对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;
    }
    

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

3 个答案:

答案 0 :(得分:2)

  

为什么我会选择多线程方法的异步方法?

异步方法允许您减少线程数。您可以发出异步调用,然后在完成后通知,而不是在阻塞调用中绑定线程。这使得线程可以在此期间进行其他处理。

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

  

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

查看在Java 8中添加的CompletableFuture。这是一个比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);
    });
}

答案 1 :(得分:1)

  

为什么我要在多线程方法上选择异步方法

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

  

Java期货应该是非阻塞的吗?

非阻塞操作通常使用Future,但是对象本身是阻塞的,但只有在你等待时才会阻塞。

  

非阻止是什么意思?

当前线程不会等待/阻止。

  

为什么在从Future&lt;中提取信息的方法时将其称为非阻塞? some-object&gt;即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;
     });
}

答案 2 :(得分:1)

我不是多线程的大师,但我也会为了自己的缘故尝试回答这些问题

  

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

多线程正在使用多线程,除此之外别无其他。一个有趣的概念是多线程不能以真正的并行方式工作,因此将每个线程分成小比特,以提供并行工作的错觉。

1

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

2

另一个例子是等待长时间的http调用。假设你正在设计一个移动应用程序,并且用户点击下载以获得5千兆字节的文件。如果您不使用多线程,则在http调用完成之前,用户将无法执行任何操作。

值得注意的是,作为开发人员,多线程只是设计代码的一种方式。它增加了复杂性,并且不必总是这样做。

现在进行异步与同步,阻止与非阻止

这些是我在http://doc.akka.io/docs/akka/2.4.2/general/terminology.html

中找到的一些定义

异步与同步

  

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

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

非阻止与阻止

  

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

     

非阻塞操作比阻塞操作更受欢迎,因为当系统包含阻塞操作时,系统的整体进度并不是很容易保证。

我发现异步vs同步更多地指的是呼叫的意图,而阻止与非阻止指的是呼叫的结果。但是,说通常异步与非阻塞相关并且同步与阻塞相关并不是错误的。

  

2 - ; Java期货应该是非阻塞的吗?非阻塞是什么意思?当从Future&lt;中提取信息的方法时,为什么称它为非阻塞? some-object&gt;即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中的代码示例很多。 如果您有任何其他问题,请与我们联系!