gpt4 book ai didi

java - 如何在请求处理线程和 SocketChannel 选择器线程之间建立 happens-before 关系?

转载 作者:搜寻专家 更新时间:2023-10-31 19:59:56 25 4
gpt4 key购买 nike

考虑一个请求-响应协议(protocol)。

我们生成一个线程来执行 select() 循环,以便在接受的非阻塞 SocketChannel 上进行读取和写入。这可能看起来像

while (!isStopped()) {
selector.select();
Iterator<SelectionKey> selectedKeys = selector.selectedKeys().iterator();

while (selectedKeys.hasNext()) {
SelectionKey selectedKey = selectedKeys.next();
selectedKeys.remove();
Context context = (Context) selectedKey.attachment();
if (selectedKey.isReadable()) {
context.readRequest();
} else /* if (selectedKey.isWritable()) */ {
context.writeResponse();
}
}
}

其中 Context 只是相应 SocketChannel 的容器、缓冲区和读取和写入它的逻辑。 readRequest 可能看起来像

public void readRequest() {
// read all content
socketChannel.read(requestBuffer);
// not interested anymore
selectionKey.interestOps(0);
executorService.submit(() -> {
// handle request with request buffer and prepare response
responseBuffer.put(/* some response content */); // or set fields of some bean that will be serialized

// notify selector, ready to write
selectionKey.interestOps(SelectionKey.OP_WRITE);
selectionKey.selector().wakeup(); // worried about this
});
}

换句话说,我们从套接字 channel 读取,填充一些缓冲区并将处理交给其他线程。该线程进行处理并准备一个响应,并将其存储在响应缓冲区中。然后它通知选择器它想要写入并将其唤醒。

Selector#wakeup() 的 Javadoc没有提到任何发生之前的关系,所以我担心选择器线程可能会看到响应缓冲区(或某些中间对象)处于不一致的状态。

这是可能的情况吗?如果是,那么通过 Selector 循环线程传递要写入 SocketChannel 的响应的正确方法是什么? (通过一些 volatile 字段发布响应?使用 SelectionKey 附件?一些其他形式的同步?)

最佳答案

首先,您不需要通知选择器要写入。你随便写。只有在写入返回零的情况下,选择器或其线程才需要参与。

其次,happens-before 关系是选择器的三个同步级别的结果,前提是您也进行同步,如下所示。

如果选择器当前正在选择,您的代码可能会在 interestOps() 调用中阻塞。 Javadoc 不排除这种可能性。您需要按正确的顺序执行操作:

  1. 醒来。
  2. 在选择器上同步。
  3. 调用 interestOps()

(2) 和选择器自身的内部同步的组合建立了任何必要的 happens-before 关系。

关于java - 如何在请求处理线程和 SocketChannel 选择器线程之间建立 happens-before 关系?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46621500/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com