阻塞和非阻塞_异步和同步

 
简要

     阻塞和非阻塞,异步和同步的原理,以及java和linux在这方面的实现原理。

 

非阻塞和阻塞

     java io和nio涉及到阻塞和非阻塞,如select,read,write均存在阻塞和非阻塞的版本。 实现原理上,java依赖于低层linux的实现,所以原理是和linux的socket实现一致的,java只是封装。 在大部分c/c++程序员眼里,他们一定不明白为什么java要分为io和nio这2个包,因为他们熟悉的socket api,从一开始就有阻塞和非阻塞的概念,只是一个Socket选项的true和false的区别而已。

     直接看linux源代码,能了解实现阻塞和非阻塞的区别(以下代码截自socket api的accept方法):



 
      

     SS_NBIO变量是标识插口操作是否阻塞线程,tsleep是使线程睡眠的函数。如果设置了SS_NBIO为true(即值为1),则在得不到数据时返回EWOULDBLOCK,如果设置了SS_NBIO为false(即 值为 0),则在得不到数据时调用tsleep挂起等待。
     看吧,阻塞和非阻塞的accept就是这点区别。 如果有兴趣想了解tsleep的具体细节,可以看看 refer (来自《HttpClient分享.ppt》第9页到第16页), 看了之后就回明白"阻塞/唤醒的原理"。

 

异步和同步

    异步和同步的区别是什么?网上有许多 不错的答案 ,本质说的是通知机制的差异:" 同步和异步仅仅是关于所关注的消息如何通知的机制,而不是处理消息的机制. 同步的情况下,是由处理消息者自己去等待消息是否被触发,而异步的情况下是由触发机制来通知处理消息者"

同步 就是自己去等待消息,举例:
(1)通过阻塞自己,等待消息的到来
inputstream.read();
在调用 read时,应用程序会阻塞。当响应返回时(从我们正在从中读取的设备中返回),程序就会解除阻塞(read 调用返回)。

(2)非阻塞,但通过轮询,直到消息的到来
int count = socketChannel.read(byteBuffer);
while(count == 0){
    count = socketChannel.read(byteBuffer);
}
程序必须要进行忙碌等待,直到数据可用为止。

异步 就是使用某种触发机制来通知处理消息者 ,下面看看java的异步IO和linux的异步IO:

 

 Java的异步IO

      "使用某种触发机制来通知消息处理者",如果你做过GUI编程,肯定对观察者模式(Observer)很熟悉,JAVA的使用了Reactor模式,结合多线程,实现了异步通知的机制。个人觉得Reactor模式实际就是观察者模式。例子如下:


 

     网上大部分文章把这种模式归类为异步阻塞IO。不过这种模式里,既使用了阻塞的select方法,也使用了非阻塞的read/writre方法。将其称为 异 步阻塞,可能因为使用了阻塞的select方法的线程属于这个模式里主要的线程,所以称为"阻塞"。不过我们还是得记住,这种模式的特点是 "使用reactor模式和多线程实现异步的通知机制,主线程使用阻塞的select监听IO事件,其他线程使用非阻塞的read/write进行具体的事件处理"

 

 

 Linux的异步IO

    抛开Java,我们也想看看linux中的异步IO是怎么实现的? 
   linux的异步I/0有2种:使用O_ASYNC标志 和 使用aio.h

 

一 使用O_ASYNC标志
   设置了O_ASYNC标志(该标志表示插口应该接收I/O事件的异步通知),当数据就绪时,内核会向"与F_SETOWN绑定的进程"发送SIGIO信号。(个人没研究过这种方法)

 

二 使用aio.h
   linux2.5内核一些版本开始出现AIO,linux2.6则把AIO纳入了标准。
   aio 的系列方法包括aio_read,aio_write等。这系列方法调用时需要传递一个结构体参数(struct)。当IO事件响应时,就会"产生一个信 号"或"执行一个回调函数" 来完成这次 I/O 处理过程。这里,选择"产生一个信号"或"执行一个回调函数" ,可以在结构体参数里设置。
   简单地可以这样解释这系列的aio方法: aio_xx(参数:信号处理函数 或 回调函数)


(1)使用信号进行异步通知

使用信号进行进程间通信(IPC)是 UNIX 中的一种传统机制,AIO 也可以支持这种机制。应用程序需要定义信号处理程序,在产生指定的信号时就会调用这个处理程序。应用程序然后配置一个异步请求将在请求完成时产生一个信号


(2)使用回调函数进行异步通知
这种机制不会为通知而产生一个信号,而是会调用用户空间的一个函数来实现通知功能。

    看到回调函数,我又联想到"java的reactor或观察者模式"了,个人认为,AIO也可以看成是使用了观察者模式,不过AIO是在linux操作系 统层面实现,而java的异步需要使用reactor实现,比较费劲,这是因为当时还没有得到底层的AIO支持。

 

    目前看来,对于这些操作系统的特点,Java虽然无法超越而且有些落后,但是Java总是在努力:JDK7已经加入了异步I/O操作, 以Proactor模式为原型设计,实现当然依附于上述的linux的AIO原理。

 

 

 

总结

    对于阻塞和非阻塞方面,到jdk1.6为止(linux版),java的io,nio包,包含了阻塞和非阻塞的IO,是完全依赖于linux的,原理和 linux一致,linux的io有SS_NBIO选项(即可以选择阻塞或非阻塞),而java则在1.0和1.4这2个版本分别实现阻塞和非阻塞。
    对于异步和同步方面,java流行的nio框架(jdk1.6基于linux的epoll)使用reactor模式和多线程实现了异步阻塞io,不过这个实现和linux的异步aio没一点关 系;java7开始,添加了java aio的实现,原理就是基于linux的aio,java aio的出现,可能让netty等nio框架要么慢慢消失,要么升级为aio框架。

 

 

参考:
http://www.ibm.com/developerworks/cn/linux/l-async/
http://dev.firnow.com/course/6_system/linux/Linuxjs/20081012/150267.html
http://www.blogjava.net/killme2008/archive/2009/09/20/295743.html

http://www.iteye.com/articles/2813

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值