java - Rox 教程中的 Java NIOServer 真的安全吗?

标签 java multithreading nio

Rox Java NIO Tutorial有一个示例 NIO Server 类。我不相信该代码实际上是线程安全的。以下代码由某个用户类调用以通过服务器发送数据:

public void send(SocketChannel socket, byte[] data) {
    synchronized (this.pendingChanges) {
        this.pendingChanges.add(new 
            ChangeRequest(socket, ChangeRequest.CHANGEOPS, SelectionKey.OP_WRITE));

        synchronized (this.pendingData) {
            List queue = (List) this.pendingData.get(socket);
            if (queue == null) {
                queue = new ArrayList();
                this.pendingData.put(socket, queue);
            }
            queue.add(ByteBuffer.wrap(data));
        }
    }
    this.selector.wakeup();
}

这是他们用于 run() 方法的相关代码:

while (true) {
    try {
        synchronized (this.pendingChanges) {
            Iterator changes = this.pendingChanges.iterator();
            while (changes.hasNext()) {
                ChangeRequest change = (ChangeRequest) changes.next();
                switch (change.type) {
                    case ChangeRequest.CHANGEOPS:
                    SelectionKey key = change.socket.keyFor(this.selector);
                    key.interestOps(change.ops);
                }
            }
            this.pendingChanges.clear();
        }

        this.selector.select();
        ...
    }
}

我的问题是,如果在主循环期间发生上下文切换,在同步块(synchronized block)之后但在调用 select() 之前调用公共(public)发送方法,那么有可能只保留写入直到下一个数据已写入或准备好读取(选择器键不会更新为写入,并且选择器不会接收唤醒信号)。就我的目的而言,这是 Not Acceptable (如果属实),但我不能仅仅为了适应这种边缘情况而对功能进行太多更改(例如为选择添加超时)。我试图想出一种方法来更好地同步各个部分,或者确保在发生上下文切换之前调用 select,但我陷入了困境。

编辑:由于对并发问题有些困惑,我将在这里更清楚地说明它。

运行线程:进入同步块(synchronized block),没有挂起的更改。

运行线程:退出同步块(synchronized block)。

调度程序:上下文切换。

其他线程:调用send方法。

其他线程:将挂起的更改和挂起的数据排入队列

其他线程:调用selector.wakeup()

调度程序:上下文切换。

运行线程:在selector.select()上阻塞,忽略待处理的数据。

运行线程:如果没有人尝试再次使用套接字,则继续永远阻塞。

我认为这涉及 NIO 和多线程的原因是因为我正在寻找一种正确同步 selector.select() 方法的方法。

最佳答案

the selector wouldn't receive the wakeup signal

then trying to wake up the selector (which does nothing because the selector isn't being selected on)

不真实。请参阅Javadoc :

If no selection operation is currently in progress then the next invocation of one of these methods will return immediately unless the selectNow() method is invoked in the meantime.

关于java - Rox 教程中的 Java NIOServer 真的安全吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39087029/

相关文章:

java - 创建一个 Jar - 出现空白屏幕

java - 什么时候应该将方法声明为同步?

Java多线程删除同组表

java - Paths.get 找不到文件 Windows 10 (java)

java - 为什么从 ByteBuffer 的绝对读取不被认为是线程安全的?

java - 关于java中自动强制转换的问题?

java - hibernate - 约束名称

java - 如何在android中校准方向传感器?

mysql - 无法在 mysql 中设置线程堆栈大小

Java NIO - 非阻塞 channel 与异步 channel