Java:SelectionKey.interestOps(int)不是线程安全的吗?

时间:2012-07-17 13:24:17

标签: java multithreading selector nio

在我的应用程序中,我使用多个线程来处理客户端连接。

我在调试时发现了一个非常奇怪的行为 - 我有一个SelectionKey,它通过调用(使用调试器)其interestOps()方法返回值为1(READ),但是当我将数据发送到与该键对应的套接字时选择器没有醒来..

如果使用调试器,我将特定选择键的兴趣操作更改为1(即使它为1),选择器会突然对该更改做出反应。

我在给定时间只有一个线程处理连接但该线程并不特定于该连接,如果我禁用多线程(将线程池设置为大小为1),则此问题从未发生过。

通过查看SelectionKey类文档 - 这个方法应该是线程安全的 - 我错过了什么?

4 个答案:

答案 0 :(得分:3)

这不是线程安全的问题。如果当前正在进行select(),则它已经读取了所有已注册密钥中的所有interestOps,并且正在选择那些读取时的值:这些值将传递给操作系统和操作系统阻止操作正在进行中。在select操作的中间更改interestOps不会影响该选择操作,只会影响下一个操作。

答案 1 :(得分:2)

在我将所有更改移到interestOps上以便在选择器线程上完成后问题得以解决 - 所以我认为interestOps(int)不是线程安全的。

修改
通过将所有的interestOps更改移动到选择器线程,我也获得了30%的加速 - 不知道为什么,但这是我的测试之间唯一的变化..

答案 2 :(得分:0)

我参加派对有点晚了,但对于像我这样的人来说,将来会访问:

"多个并发线程可以安全地使用选择键。通常,读取和写入兴趣集的操作将与选择器的某些操作同步。"

取自"SelectionKey in Java 7"

答案 3 :(得分:0)

(对不起,您的评论很晚,但是我认为最好澄清一下) 如javadoc所说(https://docs.oracle.com/javase/8/docs/api/java/nio/channels/SelectionKey.html):

  

此同步的确切执行方式取决于实现方式:在幼稚的实现方式中,如果选择操作已在进行中,则兴趣组的读写可能会无限期地阻塞;在高性能的实现中,读取或写入兴趣集可能会短暂阻塞(如果有的话)。无论如何,选择操作将始终使用该操作开始时当前的兴趣设置值。

因此,要完全理解原始问题,我们需要知道它发生在哪个环境(操作系统,内核版本,jdk版本)中。

(抱歉,我应该以内嵌评论的形式发送它,但不允许这样做)


修改:

根据更现代的jdk的文档(java 11+),SelectionKey应该是线程安全的:https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/nio/channels/SelectionKey.html

更具体地说,SelectionKey#interestOps​(int ops)应该

  

可以随时调用。如果在选择操作进行时调用此方法,则此方法对该操作无效;下次选择操作将看到对密钥兴趣集的更改。