3

AsynchronousByteChannel.read()的 Javadoc说操作是异步进行的,但是当到达流的末尾时会发生什么?是否允许在调用 read() 的同一线程中触发完成处理程序?从实现的角度来看,没有理由异步执行此操作,因为我们已经知道结果。类似地,如果用户尝试读取剩余()返回 0 的 ByteBuffer,我们知道读取操作必须返回 0。

我问是因为我在自己的 AsynchronousByteChannel 实现中遇到了竞争条件。我正在调用一个完成处理程序,该处理程序在操作完成时对其自身调用 notify()。然后我调用以下用户代码:

CompletionHandler<?, ?> handler = ...;
synchronized (handler)
{
  asyncByteChannel.read(handler);
  handler.wait();
}

请注意,用户假设操作完成时将通知处理程序,但由于 read() 实际上同步调用完成处理程序,它在 wait() 之前得到通知,后者将永远阻塞。

规范是否要求我在单独的线程中更新 CompletionHandler,或者用户是否应该知道调用 read() 的线程可能会同步执行某些操作?

4

2 回答 2

1

即使处理程序在另一个线程上被调用,也不能保证它会在方法返回后被read调用,即在你wait()启动之后。(好吧,同步锁似乎可以保证这一点。)

您应该使用同步和布尔变量来等待和锁定:

CompletionHandler<?, ?> handler = ...;
synchronized (handler)
{
   asyncByteChannel.read(handler);
   while(!handler.finished) {
     handler.wait();
   }
}

...然后您的处理程序会将finished变量设置为true。

于 2011-07-12T15:34:31.437 回答
1

查看http://www.docjar.com/html/api/sun/nio/ch/AsynchronousSocketChannelImpl.java.html他们总是在单独的线程中更新 CompletionHandler,但 Future 在同一个线程中更新。搜索变量hasSpaceToRead以查找相关方法。

我猜他们的推理路线是这样的:

  1. 我们创建了返回给用户的 Future,因此在我们返回对象之前他无法与之交互(同步等)。
  2. 用户创建了 CompletionHandler,因此我们无法控制实现的功能(据我们所知,我们可能会触发死锁!)。不要冒险,在单独的线程中触发完成处理程序。

更新:我的立场得到纠正。根据Invoker.invoke() “如果当前线程在通道组的线程池中,则直接调用处理程序,否则间接调用。”

已解决:根据http://download.oracle.com/javase/7/docs/api/java/nio/channels/AsynchronousChannelGroup.html “I/O 操作立即完成,并且启动线程是池中的线程之一组中的线程,则完成处理程序可以由启动线程直接调用。”

于 2011-07-12T16:50:05.923 回答