V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
wanderlustLee
V2EX  ›  Java

Java NIO 到底是异步还是同步,阻塞还是非阻塞?

  •  1
     
  •   wanderlustLee · 2018-07-29 14:04:52 +08:00 · 10565 次点击
    这是一个创建于 2344 天前的主题,其中的信息可能已经有所发展或是发生改变。

    今天刚刚学习 NIO,网上看了好多资料,有说是异步阻塞的,还有说是同步非阻塞的。好像是因为关注点不同,select 线程是阻塞的?对多个流处理又是非阻塞的?有大神来解释一下吗。。。

    24 条回复    2018-07-31 00:09:45 +08:00
    woncode
        1
    woncode  
       2018-07-29 14:21:48 +08:00 via Android
    只记得是非阻塞

    从百度百科看异步的定义
    『异步的另外一种含义是计算机多线程的异步处理。与同步处理相对,异步处理不用阻塞当前线程来等待处理完成,而是允许后续操作,直至其它线程将处理完成,并回调通知此线程。』

    这么说非阻塞那就是异步了
    wanderlustLee
        2
    wanderlustLee  
    OP
       2018-07-29 14:36:57 +08:00
    @woncode 但有人说异步是对于操作系统通知线程的,而 NIO 还是启了一个线程去监听事件的。所以说是同步。。。。有点懵
    xhystc
        3
    xhystc  
       2018-07-29 14:50:17 +08:00 via Android
    nio 的多路复用是属于同步非阻塞
    Srar
        4
    Srar  
       2018-07-29 14:53:56 +08:00
    底层已经改成 epoll Selector 底层初始化时候回申请一个 128 长度的事件数组 当 epoll 通知事件时候 jvm native 层会直接往这事件数组里插事件 你要做的事就是把事件拿出来。。。
    alamaya
        5
    alamaya  
       2018-07-29 14:54:52 +08:00
    nio 底层就是 epoll 当然是同步非阻塞的
    hecz
        6
    hecz  
       2018-07-29 15:01:07 +08:00
    @wanderlustLee 同步和异步的区别就是同步会在整个 io 操作中导致进程阻塞,而异步不会。异步非阻塞 IO 只属于这种情况,就是我发送一个 io 请求,操作系统帮你做好各种事,包括获取 io 流,以及将 io 流从内核拷贝到用户空间,你只需要收到完成的通知即可。而 NIO 是多路复用 IO,他虽然在获取内核的数据时不会阻塞,但是它却会在将内核数据拷贝到用户空间的时候线程阻塞。所以 NIO 是同步非阻塞。
    lhx2008
        7
    lhx2008  
       2018-07-29 15:02:01 +08:00 via iPhone   ❤️ 1
    按照某大神书上的理论,是叫做同步非阻塞,不过我觉得他开心就好。

    按照我的理解,默认实现是,分配 channel 可以线程复用,即每一个线程可以同时绑定多个 channel (传统的只能绑定一个),那么这样这个线程的空闲时间会比较少,效率会比较高。

    然后,每个线程中默认是阻塞或者叫同步的,就是和传统的没差。该花的时间还是要花。

    再之后,我们可以在 NIO 的基础上改成异步的,就是一个线程不光可以处理 channel 上面的用户事件,还可以执行我们自己定义的事件。在处理 channel 事件时,不阻塞马上返回,并且把相关的操作打包成一个事件,并且告诉这个事件干完这件事情(这个可能不是自己干而是别人干),还要干什么事情。然后这个事件也在这个线程的排队队列中处理。这样可以进一步压缩这个线程的空闲时间。这就是 NETTY 的实现。只需要少量的线程就可以得到比较高的效率。

    当然,你可能觉得上面的这样做效率并没有什么提高,那么,我们还可以再维护一个稍大的池子专门处理阻塞时间比较久的事件的线程池。这是 Vertx 里面对 netty 的改进。
    nl101531
        8
    nl101531  
       2018-07-29 15:04:28 +08:00 via Android   ❤️ 2
    同步非阻塞,同步体现在 selector 仍然要去轮循判断 channel 是否准备好,非阻塞体现在这个过程中处理线程不会一直在等待,可以去做其他的事情。
    pkaq
        9
    pkaq  
       2018-07-29 15:07:27 +08:00
    Blocking IO/ Non-Blocking IO / asynchronous I/O
    coldear
        10
    coldear  
       2018-07-29 15:08:03 +08:00
    是同步非阻塞的( non-blocking IO)。
    从 channel 读的时候,不确定能读出多少,会立刻返回当前能读到的东西。你的代码得处理这些情况,可以干别的事情之类。
    selector 是说你可以注册多个 channel,你的代码可以不停的去调用 select(), 当有 IO 可以读取的时候,你可以处理,没有的话你可以在代码里干别的事。
    NIO 总之是为了代码不要被 IO 阻塞,但代码写起来相对麻烦一点。
    nl101531
        11
    nl101531  
       2018-07-29 15:08:42 +08:00   ❤️ 6
    @nl101531 补充下,同步异步关注点是你问内核数据有没有准备好,还是内核主动通知你数据有没有准备好。阻塞非阻塞关注点时你的处理线程在数据没有准备好的时候是一直在等待状态还是可以去做其他的事情。
    twogoods
        12
    twogoods  
       2018-07-29 15:18:42 +08:00
    select 确实是阻塞的,但没有一个请求线程会是阻塞的,同步非阻塞
    WordTian
        13
    WordTian  
       2018-07-29 15:31:26 +08:00 via Android
    看看 netty 权威指南前两章吧,那块有几个流程图把这个区别解释的很清楚
    zmxnv123
        14
    zmxnv123  
       2018-07-29 16:05:29 +08:00
    同步非阻塞,异步的请左转看 AIO,好像 JDK1.7 引入的。
    qk3z
        15
    qk3z  
       2018-07-29 18:03:48 +08:00 via Android
    建议看看《 netty 权威指南》,讲的还是很明白的
    wanderlustLee
        16
    wanderlustLee  
    OP
       2018-07-30 08:52:08 +08:00
    @xhystc
    @Srar
    @alamaya
    @hecz
    @lhx2008
    @nl101531
    @pkaq
    @coldear
    @nl101531
    @twogoods
    @WordTian
    @zmxnv123
    @qk3z
    恩恩,明白了。肥肠感谢!
    owenliang
        17
    owenliang  
       2018-07-30 08:55:08 +08:00 via Android
    走 select 是异步,否则是同步。
    cyspy
        18
    cyspy  
       2018-07-30 09:22:19 +08:00 via Android
    很多人是把 BIO NIO AIO 并列
    wanderlustLee
        19
    wanderlustLee  
    OP
       2018-07-30 09:35:50 +08:00
    @nl101531 老哥说的很形象,理解了
    wanderlustLee
        20
    wanderlustLee  
    OP
       2018-07-30 09:38:27 +08:00
    @lhx2008 那么在 NIO 中的绑定多个 channel 的线程是不可以去做其他的事情吗,只能用来处理这些 channel 吗?
    wanderlustLee
        21
    wanderlustLee  
    OP
       2018-07-30 09:41:11 +08:00
    @hecz epoll 中不是会有事件通知线程吗?这种行为和真正的异步区别在哪里...
    lhx2008
        22
    lhx2008  
       2018-07-30 09:49:36 +08:00
    @wanderlustLee 线程是死循环,做别的事情要异步封装事件到线程的任务队列
    wanderlustLee
        23
    wanderlustLee  
    OP
       2018-07-30 10:32:28 +08:00
    @lhx2008 也就是说 java 中的普通 NIO 是同步的,netty 中对 NIO 进行了异步实现吗?
    hecz
        24
    hecz  
       2018-07-31 00:09:45 +08:00
    @wanderlustLee 其实通知你是告诉你内核准备好了,你取数据的时候还是需要将内核中的数据拷贝到用户空间中。这段时间进程是会阻塞的
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1613 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 16:50 · PVG 00:50 · LAX 08:50 · JFK 11:50
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.