同步和异步通常用来形容一次方法调用。
- 同步方法调用一旦开始,调用者必须等到方法调用返回后,才能继续后续的行为。
- 异步方法调用更像一个消息传递,一旦开始,方法调用就会立即返回,调用者就可以继续后续的操作。而,异步方法通常会在另外一个线程中,“真实”地执行着。整个过程,不会阻碍调用者的工作。
-
图示例
理解IO
IO(Input/Output)通常是指计算机线程进行慈磁盘读写或者网络通信时的一种行为。
同步式(Synchronous)IO和异步式(Asynchronous )IO
同步式: 当计算机调度线程进行I/O操作命令后,由于文件的读写或者网络通信需要较长的操作时间,操作系统为了充分利用cpu,此时会暂停到当前的I/O线程对CPU的控制(故又称同步式为阻塞式I/O),把cup资源然给其他的线程资源,当I/O线程完成了操作时,此时操作系统会恢复此时的I/O线程,从而当前I/O线程重新获得了cup的的控制权,继续完成其他操作。
NodeJs让很多前端开发者利用JS开发服务器变得异常的简单,而异步式I/O则是NodeJs的一大特点。
异步式 :异步式IO又称非阻塞式I/O,异步式与同步式不同的是,当线程进行IO操作时,操作系统并不是暂停当前的线程操作,而是执行完I/O指令后,操作系统继续让当前线程执行下一条指令,当I/O操作完成后,会通过事件(event)通知I/O线程,而线程在接收到通知后,会处理响应事件。
简单的说,同步式是让通过多个线程完成多个任务,而异步式则是通过一个线程完成多个任务,遇到I/O操作时,依然让线程继续执行其他指令,只是在I/O完成后通知线程调度响应事件即可。
图解:
-
所谓同步,简单的说,A告诉B去做某件事情,然后就一直等待,直到B做完后返回给A,A才继续做其它的事情;
所谓异步,相反的,A告诉B做某件事情,然后就去干其它的事情了,B做完后再通知A。
无论是同步还是异步,其实都是指两个对象之间的交互。所以,判断什么是同步还是异步,首先要先明确指的是哪两个对象之间的关系。
举个例子:
- socket.write(request);
- response = socket.read();
这是一段常见的伪代码,用于Client向Server发送请求。在这里,可以说socket.write是一个同步IO,因为调用write操作以后,内核会将要写的数据放入到网卡的缓冲区中,然后再返回,所以,这里同步的两个对象分别是应用程序和内核;也可以说这段代码是一个同步消息机制,因为client将request发送给server后,一直等待直到server将response返回,这里同步的两个对象分别是client和server。
之前的那篇blog专门论述同步IO和异步IO,它指的是应用程序和操作系统内核间的关系。这里就不多谈了。这里谈谈Mina。Mina是一个非常流行的网络程序的框架,它提供的是异步的API(It provides an abstract • event-driven • asynchronous API)。
比如,如果client想要创建一个到server的连接,用mina可以这样写:
- NioSocketConnector connector = new NioSocketConnector();
- // 初始化connector...
- //..........
- connector.connect(address);
看上去好像和一般的写法没什么两样。但是,这里的connector.connect()方法是一个异步的调用,意思是程序告诉mina要去连接address,mina返回说它会做这件事,但它可能还没有做完。所以,即便“connector.connect(address);”这行代码结束了,也并不意味着连接成功了(mina这时候可能还正在创建连接的过程中)。完整的写法应该是:
- ConnectFuture connFuture = connector.connect(address);
- connFuture.addListener(new ConnectListener());
- private class ConnectListener implements IoFutureListener<ConnectFuture>{
- public void operationComplete(ConnectFuture future) {
- if (future.isConnected()) {
- //get session
- IoSession session = future.getSession();
- session.write(...);
- } else {
- logger.error("can not create the connection .");
- }
- }
- }
- }
- }
这里面最重要的一个类是ConnectListener,它实现了IoFutureListener<ConnectFuture>这个接口。这个类其实只有一个函数 – operationComplete,这是一个回调函数,它告诉mina一旦connect完成以后,就调用这个函数。我们这里的回调函数,首先判断一下连接是否成功,如果成功,那么就向这个链接中写入数据(session.write)。
回调函数在异步机制中扮演着非常重要的角色。因为在同步机制中,调用者会等到结果返回然后自己执行接下来的操作,比如,上面这段代码如果写成同步的,大概是这个样子:
- boolean status = connector.connect(address);
- if(status) {
- session.write(...);
- } else {
- logger.error("can not create the connection .");
- }
但是在异步机制中,就只能将connect后面的代码做成回调函数,注册到mina中。这样,当mina完成工作后它才知道接下去该干什么。
值得一提的是,虽然Mina号称是Asynchronous API,但它也提供了同步的方法。比如,上面这段代码,如果用Mina的同步机制是这样写的:
- ConnectFuture future = connector.connect(address);
- future.awaitUninterruptibly();
- IoSession session = future.getSession();
- // Send the first ping message
- session.write(....);
同步~异步~阻塞~非阻塞
同步调用~异步调用~阻塞调用~非阻塞调用