Java中的某些方法会阻塞,直到它们能够执行某些操作,比如ServerSocket.accept()和InputStream.read(),但是这样做对我来说并不容易找到。我能想到的最接近的事情是每次循环使用Thread.sleep()的while()循环,但是睡眠时间越长,阻塞响应越少,睡眠越短,发生的旋转越多。
我有两个问题:
各种标准功能(如上所述)如何阻止?原生代码? while()循环?别的什么?
我应该如何实现阻止的方法?
答案 0 :(得分:10)
由于底层平台(即本机代码),您列出的操作会被阻止。
您可以使用Java的Object.wait()
和Object.notify()
方法实现一个块; wait()
将阻塞调用线程,直到另一个线程在同一个锁上调用notify()
。
答案 1 :(得分:6)
(1)的基本答案是“不要担心它 - 操作系统处理它”。调用从输入流中读取的内容实际上是围绕操作系统调用的包装。在操作系统内部,我认为通常在这些情况下调用“阻塞”时,操作系统“知道”它正在等待硬盘中断,比如磁盘控制器说这样 - 和 - 这些请求的数据现在可用,并且它知道线程X是请求该数据的数据。因此它不会再次在线程X中进行调度,直到它收到该中断(或中断说“有错误”等)。 (然后,线程调度算法的一部分就是在等待的数据变得可用时给等待线程一个临时的“提升”。同样,通常你不需要太担心这个。)或者换一种方式:无论这种机制的具体细节如何,一般的Java程序员都无法使用它。
在(2)中,我建议更多地思考“我怎么做可能碰巧阻止的事情X”。我认为答案几乎没有“你想要做的事情”故意只是“阻止”,而无论Thing X是什么,都可能有一个库方法/类会为你做。例如(链接包括我在这些主题上写的一些材料):
我会说使用Java 5并发API很大程度上不推荐使用原始等待/通知机制。无论你做什么,自旋锁通常是最后的手段。
答案 2 :(得分:4)
要回答(2)你想要Object方法wait,notify和notifyAll。
使用Object.wait()时,必须将wait括在一个循环中,该循环检查您正在等待的条件。 wait()方法可以虚假返回(出于微妙的原因)。
此外,您需要考虑是否需要使用notify()或notifyAll() - 如果所有等待的线程都在等待完全相同的条件,并且您只需要处理它正在通知的任何内容因为,您可以使用notify(),否则您需要使用notifyAll(),因为您无法保证在notify()上通知哪个线程 - 例如,您不能指望它们是循环的。
最后,请确保您查看java.util.concurrent包 - 与使用Java原语相比,它具有许多更高级别和更好的解决常见线程问题的解决方案。
答案 3 :(得分:2)
我可以回答第1部分。他们使用操作系统来处理它,因为每个操作系统已经内置信号和阻塞作为启用多任务的一部分。
通常,如果你必须实现自己的旋转锁定代码,那么你要么使用错误的方法。旋转还可以减少任何形式的电源管理,即使在良好的睡眠状态下,代码仍然必须醒来才能做任何事情。