同步调用与异步调用

同步
        所谓同步,就是在发出一个功能调用时,在没有得到结果之前,该调用就不返回。也就是必须一件一件事做,等前一件做完了才能做下一件事。按照这个定义,其实绝大多数函数都是同步调用。但是一般而言,我们在说同步、异步的时候,特指那些需要其他部件协作或者需要一定时间完成的任务。最常见的例子就是SendMessage。该函数发送一个消息给某个窗口,在对方处理完消息之前,这个函数不返回。当对方处理完毕以后,该函数才把消息处理函数所返回的
LRESULT值返回给调用者。

异步
        异步的概念和同步相对。当一个异步过程调用发出后,调用者不能立刻得到结果。实际处理这个调用的部件在完成后,通过状态、通知和回调来通知调用者。以CAsycSocket类为例,当一个客户端通过调用Connect函数发出一个连接请求后,调用者线程立刻可以朝下运行。当连接真正建立起来以后,socket底层会发送一个消息通知该对象。

同步函数

        当一个线程调用一个同步函数时,如果该函数没有立即完成规定的操作,则该操作会导致该调用线程的挂起(将CPU的使用权交给系统,让系统分配给其他线程使用),直到该同步函数规定的操作完成才返回,最终才能导致该调用线程被重新调度。

异步函数
        当一个线程调用的是一个异步函数,该函数会立即返回尽管其规定的任务还没有完成,这样线程就会执行异步函数的下一条语句,而不会被挂起。那么该异步函数所规定的工作是如何被完成的呢?当然是通过另外一个线程完成的了啊;那么新的线程是哪里来的呢?可能是在异步函数中新创建的一个线程也可能是系统中已经准备好的线程。

如何同步获取异步调用的结果

一个调用了异步函数的线程如何与异步函数的执行结果同步呢?
        为了解决该问题,调用线程需要使用“等待函数”来确定该异步函数何时完成了规定的任务。因此在线程调用异步函数之后立即调用一个“等待函数”挂起调用线程,一直等到异步函数执行完其所有的操作之后,再执行线程中的下一条指令。

如何异步获取异步调用的结果

异步调用时,调用方不等被调方返回结果就转身离去,因此必须有一种机制让被调方有了结果时能通知调用方,常用的手段是回调。
        回调方式很简单:调用异步函数时在参数中放入一个函数地址,异步函数保存此地址,待有了结果后回调此函数便可以向调用方发出通知。如果把异步函数包装进一个对象中,可以用事件取代回调函数地址,通过事件处理例程向调用方发通知。

同步调用如何转换成异步调用

       其实同步调用与异步调用很容易进行转换:如果想要把一个同步调用转换成异步调用,只需要一个线程或一组线程加上消息队列即可。根据异步调用处理工作完成的方式,可以将其细分成三类:1)甩手掌柜,不管;2)做个标记,让调用者需要时询问。“帮我买个馒头”-“馒头买好了没有?”-“馒头买好了没有?”3)直接回调,如“帮我买个馒头,买好后放在我包里”。


       在以前的文章中,我曾多次强调应用程序中异步化的重要性。尤其对于IO密集型操作来说,异步执行对于应用程序的响应能力和伸缩性有非常关键的影响。 正确使用异步编程能够使用尽可能少的线程来执行大量的IO密集型操作。可惜的是,即使异步编程有避免线程阻塞等诸多好处,但是这种编程方式至今没有被大量 采用。其原因有很多,其中最主要的一点可能就是异步模型在编程上较为困难,导致许多开发人员不愿意去做。

       异步,则意味着一个任务至少要被拆分为“二段式”的调用方式:一个方法用于发起异步请求,另一个方法用于异步任务完成后的回调。与传统方法的调用方 式相比,异步调用时的中间数据不能存放在线程栈上,方法之间的也不能简单地通过参数传递的方式来共享数据。此外,传统方法调用中可使用的 try…catch…finally,using等关键字都无法跨越方法边界,因此异步编程在处理异常,保护资源等方面也需要花更大的精力才行。如果一不 小心,轻则造成资源泄露,重则使整个应用程序崩溃。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
当涉及到网络请求时,同步调用异步调用可以用以下示例来说明: 1. 同步调用示例: 假设我们需要通过网络请求获取某个网站的数据,并将其打印出来。在同步调用中,代码会在发送请求后等待响应返回后再继续执行。 ```java import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.URL; public class SyncExample { public static void main(String[] args) { try { // 创建URL对象 URL url = new URL("https://example.com"); // 打开连接并获取输入流 BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream())); // 读取数据并打印 String line; while ((line = reader.readLine()) != null) { System.out.println(line); } // 关闭连接 reader.close(); } catch (IOException e) { e.printStackTrace(); } // 其他代码... } } ``` 在这个示例中,`url.openStream()` 是一个同步调用,它会阻塞代码的执行直到数据完全加载并返回。 2. 异步调用示例: 现在我们使用异步调用来实现相同的功能。在异步调用中,代码会在发送请求后继续执行,不会等待响应的返回。 ```java import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.URL; import java.util.concurrent.CompletableFuture; public class AsyncExample { public static void main(String[] args) { // 创建URL对象 URL url; try { url = new URL("https://example.com"); // 使用CompletableFuture来进行异步请求 CompletableFuture.supplyAsync(() -> { try { // 打开连接并获取输入流 BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream())); // 读取数据并返回 StringBuilder response = new StringBuilder(); String line; while ((line = reader.readLine()) != null) { response.append(line); } // 关闭连接 reader.close(); return response.toString(); } catch (IOException e) { e.printStackTrace(); } return null; }).thenAccept(response -> { // 异步操作完成后执行的回调,打印响应结果 System.out.println(response); }); } catch (IOException e) { e.printStackTrace(); } // 其他代码... } } ``` 在这个示例中,我们使用了`CompletableFuture`来进行异步请求。`url.openStream()` 被包装在一个异步任务中,当任务完成后会调用 `thenAccept` 方法指定的回调函数来处理响应结果。这样,在请求发送后,代码会立即继续执行,不会等待响应返回。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值