账号密码登录
微信安全登录
微信扫描二维码登录

登录后绑定QQ、微信即可实现信息互通

手机验证码登录
找回密码返回
邮箱找回 手机找回
注册账号返回
其他登录方式
分享
  • 收藏
    X
    nio使用线程处理每一个读写请求的写法问题
    30
    0

    问题描述

    在写java nio的demo时,希望按照React的模式实现,对每一个已经就绪的请求,都在一个新的线程里处理。具体的代码如下面所示。

    当一个客户端写完数据之后,断开连接时,会报错:

    java.nio.channels.ClosedChannelException

    显然这种写法是不合适或者不对的。看到网上用的是 attach() 方法

    selectionKey.attach(new Acceptor(selector,selectionKey));

    那么:
    问题1: 我采用的写法,是哪里导致客户端关闭时报错,错误原因是什么?
    问题2: attach()怎么用,为什么这种写法可以避免关闭客户端报错的情况?

    相关代码

    使用单独线程,进行select操作。

    new Thread(() -> {
                try {
                    while (selector.select() > 0) {
                        for (SelectionKey selectionKey : selector.selectedKeys()) {
                            try {
                                selector.selectedKeys().remove(selectionKey);
                                if (selectionKey.isAcceptable()) {
                                    SocketChannel socketChannel = serverSocketChannel.accept();
                                    socketChannel.configureBlocking(false);
                                    socketChannel.register(selector, SelectionKey.OP_READ);
                                }
                                if (selectionKey.isReadable()) {
                                    doRead(selectionKey);
                                    
                                }
                            } catch (IOException e) {
                                selectionKey.cancel();
                            }
                        }
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }).start();

    当遇到可读事件时,在一个新的线程里进行处理。

    public void doRead(SelectionKey selectionKey) {
            new Thread(() -> {
                try {
                    SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
                    ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
                    String content = "";
                    int c = 0;
                    while ((c = socketChannel.read(byteBuffer)) > 0) {
                        byteBuffer.flip();
                        content += charset.decode(byteBuffer);
                    }
                    System.out.println(content);
                    selectionKey.interestOps(SelectionKey.OP_READ);
                    if (c == -1) {
                        selectionKey.cancel();
                        socketChannel.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }).start();
        }
    0
    打赏
    收藏
    点击回答
        全部回答
    • 0
    • 萌新也要冲 普通会员 1楼

      NIO(New IO)是一种面向多路复用的输入/输出流,它可以同时处理多个输入/输出请求,大大提高了系统的并发性。

      在NIO中,每个线程都有自己的输入和输出流,所以每个线程都可以独立地处理读写请求。这种方式可以大大提高系统的并发性,因为多个线程可以同时处理多个读写请求,而不会互相影响。

      以下是一个简单的例子,展示了如何在NIO中使用线程处理每一个读写请求:

      ```java import java.io.IOException; import java.nio.channels.FileChannel; import java.nio.channels.ReadableByteChannel; import java.nio.channels.WritableByteChannel; import java.nio.channels.Channels; import java.nio.channels.ReadableByteChannel; import java.nio.channels.WritableByteChannel;

      public class NioExample { public static void main(String[] args) throws IOException { FileChannel fileChannel = Channels.open("test.txt", 0644); ReadableByteChannel readableChannel = Channels.newChannel(fileChannel); WritableByteChannel writableChannel = Channels.newChannel(fileChannel);

          // 线程1:读取
          Thread thread1 = new Thread(() -> {
              try {
                  readableChannel.readAllBytes();
                  System.out.println("Read from " + readableChannel);
              } catch (IOException e) {
                  e.printStackTrace();
              }
          });
      
          // 线程2:写入
          Thread thread2 = new Thread(() -> {
              try {
                  writableChannel.writeAllBytes("Hello, World!");
                  System.out.println("Write to " + writableChannel);
              } catch (IOException e) {
                  e.printStackTrace();
              }
          });
      
          thread1.start();
          thread2.start();
      
          thread1.join();
          thread2.join();
      }
      

      } ```

      在这个例子中,我们创建了两个线程,一个线程负责读取文件,另一个线程负责写入文件。这两个线程可以在不阻塞主线程的情况下同时运行。

      注意,这个例子使用了Java的NIOAPI,如果你的系统不支持NIO,你可能需要使用其他的并发编程库,如Java并发包(java.util.concurrent)或C++的std::thread。

    更多回答
    扫一扫访问手机版
    • 回到顶部
    • 回到顶部