2012-07-17 102 views
0

在我的应用程序中,我使用多个线程来处理客户端连接。我有一个SelectionKey,通过调用(使用调试器)它的interestOps()方法的返回值是1(READ),但是当我发送数据到相应的套接字键选择器不会醒来。Java:SelectionKey.interestOps(int)不是线程安全的?

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

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

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

+0

两者你真的步入源代码? javadoc并不总是提到一个方法是否是线程安全的。 – user1329572 2012-07-17 13:31:06

+0

@ user1329572是的,该方法做了2件重要的事情 - 更改自己感兴趣的操作字段,然后调用通道的translateAndSetInterestOps方法 - 这是我认为问题发生的地方,但正如我所说 - 我只有一个线程处理连接时间,我也在同步密钥时更改其interestOp,但没有修复bug .. – bennyl 2012-07-17 13:37:47

回答

2

这个问题是在我将感兴趣的所有更改移到选择器线程上后解决的 - 所以我猜这个interestOps(int)不是线程安全的。

编辑
由所有interestOps改变移动到选择线程我也收获了30%的加速 - 不知道为什么,但是这是我的测试之间的唯一的变化..

2

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

+0

我在唤醒每个键更改后的选择器 - 这没有帮助..我甚至使用select(int)方法超时只是10秒,看看这种行为是否可以使用选择器“固定” - 事实并非如此。 – bennyl 2012-07-18 07:46:12

0

我有点迟到了,但人谁都会像我一样,在参观未来:

“选择键是由多个并发线程安全的读操作和通常,写兴趣集将与选择器的某些操作同步。“

"SelectionKey in Java 7"

+1

重要的是要明白,他们可以阻止选择器正在选择 - 这可能会导致死锁。所以虽然他们在术语的“正确性”方面在技术上是安全的,但他们在术语 – bennyl 2016-11-06 10:56:40

+0

的“进度”方面不太安全。是的,我学会了这一难题。一般来说,即使认为这个解决方案是以创建速度和效率的方式创建的,但它并没有达到预期。在连接到其他主机的情况下(所以当创建通道,注册选择器并设置兴趣操作)时,需要创建额外的锁,并执行如下操作:selKey.interestOps(OP_WRITE); lock.lock(); selector.wakeUp();同时连接,然后执行以下操作:选择器。选择(); synchronized(lock){};在选择器循环中 - 否则选择器可以唤醒并进入休眠状态。 – 2017-01-02 13:38:10

+1

实际上,您可以使用比锁更好的解决方案:只需创建一个'ConcurrentLinkedQueue selectorOps'字段,并在每次选择并运行该队列中的所有可运行内容后立即在该队列上运行选择器线程。然后,如果你想改变一些关键的操作,你所要做的就是调用:'selectorOps.add(() - > key.interestedOps(ops)); selector.wakeup();' - 不需要锁定。 – bennyl 2017-01-02 16:48:15