0

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

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

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

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

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

4

4 回答 4

3

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

于 2012-07-18T03:47:25.913 回答
2

在我将所有更改移动到要在选择器线程上完成的 interestOps 后,问题就解决了 - 所以我猜 interestOps(int) 不是线程安全的。

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

于 2012-07-17T14:33:36.370 回答
0

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

“选择键对多个并发线程使用是安全的。读取和写入兴趣集的操作通常会与选择器的某些操作同步。”

取自“Java 7 中的选择键”

于 2016-11-04T08:15:22.573 回答
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/选择键.html

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

可以随时调用。如果在选择操作正在进行时调用此方法,那么它对该操作没有影响;键的兴趣集的变化将在下一个选择操作中看到。

于 2019-09-27T09:15:29.937 回答