在实现依赖java nio的服务器时,以下做法似乎是标准的:
使用单个线程(和单个选择器)进行读取:
ByteBuffer buffer = . . .
selector.select()
...
channel.read(buffer)
if (isRequestComplete(buffer))
processRequest(buffer) //will run in a separate thread
void processRequest(ByteBuffer buffer)
new Thread(new Handler(buffer)).start()
是的,我正在删除大量代码
我的问题不在于从通道中选择/读取的机制,而是在与选择器线程不同的线程中读取#buffer的可见性语义。我在javadoc中什么都看不到,从线程A中的ByteBuffer读取(上面的'Handler')可以保证看到线程B中的ByteBuffer写入(上面的'Selector')。
现在,在我看来,上面的代码根本不是多线程安全的,即它是错误的。
但是我在很多教程甚至一些代码库中都看到了相同的模式(总是没有参考可见性问题);所以我想知道我是否遗漏了一些明显的东西。
注意:我特别关注“处理程序”线程只能从#buffer中读取的情况 - 它从不会将新字节写入其中
答案 0 :(得分:1)
这实际上似乎没问题。你需要的是证明在选择器线程“happens-before”中写入处理程序线程中的读取。根据内存可见性规则,同一线程中的操作按程序顺序发生。新线程的创建也确定了之前发生的事情。所以写入发生在创建线程之前 - 在读取之前发生。
如果你将它传递到例如ExecutorService
。