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

Fin*_*ber 3 java io multithreading

我知道非阻塞 IO 不会阻塞调用线程,而是在等待 IO 时释放它来做其他事情。

我刚刚了解了Thread. yield允许线程告诉 CPU 运行其他线程的方法......技术上产生控制。

这两个东西,非阻塞 IO 和Thread. yield听起来和我很相似,所以我想知道,在最基本的层面上,非阻塞 IO 是Thread. yield在做 IO 时才使用的吗?

Kay*_*man 5

TL;DR:不,Thread.yield()不能也不应该用于任何事情

该机制可能看起来类似,但yield()与非阻塞 IO 无关且不能用于实现非阻塞 IO。它也很麻烦,行为取决于平台,因此不应使用

虽然阻塞 IO 的工作原理是让一个线程在输入流上“锁定自己”并在输入到达时唤醒,但非阻塞 IO 会逆转这一点,并且有一个中央选择器(一种本地机制)在输入数据可用时得到通知。它可以同时观察数千个频道,在不需要任何关注的频道上花费零资源。当通道上的数据可用时,选择器然后将该数据定向到工作线程进行处理。它是高效的,但也不同于阻塞 IO 并且更复杂。

由于yield()只告诉CPU“我没有工作要做,休息时可以随意运行其他线程”,因此它仍然以与常规IO相同的方式工作。您想避免无事可做的线程,而让步就是主动不做任何事情,而不是让调度程序确定它。

现在您可能认为您可以编写类似以下内容来模拟非阻塞 IO

List<InputStream> ins ...
while(true) {
    for(InputStream in : ins) {
        if(in.available() > 0) {
            int input = in.read();
            // do something with input
        }
    }
    Thread.yield();
}
Run Code Online (Sandbox Code Playgroud)

您可能认为代码的作用就像一个选择器。通过阻塞输入流,检查它们是否有数据要读取,如果有,读取数据并处理它,并且可能在循环之后产生线程以进行良好的测量。

上面的代码有缺陷,主要是因为调用了InputStream.available(). 如果调用返回正数,它可用于判断何时不会阻塞,但它可以返回但0仍然不会阻塞。您可能(并且很可能会)最终永远循环这些流而不读取任何内容,因为逻辑认为它会阻塞,因为available()返回0只是因为它无法确定它不会阻塞。这是阻塞和非阻塞 IO 之间的主要区别。知道读取是否会被 BIO 阻塞的唯一确定方法是调用read(). 然后你可能会被卡住。

这是斯蒂芬对套接字编程中可用()问题的很好解释。