Thread.yield与Java中的非阻塞IO是否相同?

3
我知道非阻塞IO不会在调用线程上阻塞,而是释放它去做其他事情,同时等待IO。
我刚学了一个叫做Thread.yield的方法,它允许一个线程告诉CPU运行其他线程...技术上让出控制权。
这两件事,非阻塞IO和Thread.yield听起来很相似,所以我想知道,在最基本的层面上,非阻塞IO只是在进行IO时使用了Thread.yield吗?

@Kayaman 为什么不把你的评论变成答案呢? - Basil Bourque
@Kayaman,那听起来对我来说是一个相当好的答案。 - dreamcrash
1个回答

5
TL;DR:不,Thread.yield()不能也不应该用于任何事情。
虽然机制看起来相似,但yield()与非阻塞IO无关,也不能用于实现非阻塞IO。它也很麻烦,行为取决于平台,因此不应该使用
阻塞IO通过在输入流上“锁定自身”并在输入到达时唤醒线程来工作,而非阻塞IO则将其反转,有一个中央选择器(一种本地机制)在输入数据可用时得到通知。它可以同时观察数千个通道,并在那些不需要任何关注的通道上花费零资源。当通道上有数据可用时,选择器会将该数据指示给工作线程进行处理。这是有效的,但也与阻塞IO不同且更加复杂。
由于yield()只是告诉CPU“我没有工作要做,请运行其他线程,而我休息一下”的方式,它仍然像常规IO一样工作。你希望避免那些没有任何事情可做的线程,并且主动不做任何事情而让调度程序来决定,这就是yield()的作用。
现在你可能会想写以下内容来模拟非阻塞IO
List<InputStream> ins ...
while(true) {
    for(InputStream in : ins) {
        if(in.available() > 0) {
            int input = in.read();
            // do something with input
        }
    }
    Thread.yield();
}

你可能认为代码像选择器一样起作用。通过阻塞输入流,检查它们是否有数据可读,如果有,则读取数据并处理,然后在循环后适当时候暂停线程。

上述代码主要存在缺陷是因为调用了 InputStream.available()。如果它返回正数,可以用它来告诉何时不会阻塞,但它也可以返回0而仍然不会阻塞。你可能(很可能)会无限循环这些流,并且不会读取任何东西,因为逻辑认为它将被阻塞,而available()返回0只是因为它不能确定它不会被阻塞。这是阻塞和非阻塞IO之间的主要区别。使用BIO唯一确定的方法是调用read()才能知道读取是否会阻塞。然后你可能会陷入困境。

以下是Stephen关于套接字编程中available()的问题的好解释。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接