简体   繁体   English

每个事件的 NIO 线程池

[英]NIO thread pool per event

I am using a java NIO based which accept connections from clients( configured non blocking ) and only reads data sent by clients.我正在使用基于 java NIO 的它接受来自客户端的连接(配置为非阻塞)并且只读取客户端发送的数据。 Clients once connected will stick to server for a long time, so i used a single thread for "selector.select" and "Accept", but the clients connected will send messages every 15 sec and number of clients are 5000, each message is of size 150 Bytes .一旦连接的客户端将长时间坚持服务器,所以我使用单个线程“selector.select”和“Accept”,但连接的客户端将每15 秒发送一次消息,客户端数量为 5000,每条消息是大小150 字节

Instead of creating a new thread for each read from clients i decided to have a thread pool of 100 threads, but server is not able to read data from all clients it simply hangs .我没有为每次从客户端读取的内容创建一个新线程,而是决定拥有一个包含 100 个线程的线程池,但服务器无法从所有客户端读取数据,它只是挂起 When a new thread is created each time it is able to read data from all clients.每次创建新线程时,它都能够从所有客户端读取数据。

Here is my ReadEvent thread这是我的 ReadEvent 线程

class ReadEvent implements Runnable {

    private static Logger logger = Logger.getLogger(ReadEvent.class.getName());
    private SelectionKey key;

    /**
     * Constructor to initialize the thread with the key having read event
     * pending.
     * 
     * @param key
     *            SelectionKey having read event.
     **/
    public ReadEvent(SelectionKey key) {
        this.key = key;
    }

    /**
     * Method to read the data from the key.
     **/
    @Override
    public void run() {
        SocketChannel socketChannel = (SocketChannel) key.channel();
        synchronized (socketChannel) {
            if (socketChannel.isOpen()) {
                try {
                    ByteBuffer readBuffer = ByteBuffer.allocate(150);
                    int numRead = 0;
                    try {
                        /* ".read" is nonblocking */
                        numRead = socketChannel.read(readBuffer);
                        /*
                         * Some other IO error on reading socketChannel.
                         */
                    }
                    catch (IOException e) {
                        logger.debug(
                            "[run] Connection abruptly terminated from client",
                            e);
                        key.channel().close();
                        return;
                    }
                    if (numRead == -1) {// socket closed cleanly
                        key.channel().close();
                        return;
                    }
                    String data = null;
                    data = new String(readBuffer.array(),
                        Charset.forName("ASCII"));
                    /* Send the read data to the DataDispatcher Actor */
                    Main.getDataDispatcher().tell(data, ActorRef.noSender());
                }
                catch (IOException e) {
                    logger.debug("[run] ", e);
                    return;
                }
            }
            else {// socketChannel is closed
                try {
                    key.channel().close();// Sanitary close operation
                    return;
                }
                catch (IOException e) {
                }
            }
        }
    }
}

I can't figure out the overload on thread pool, any suggestions on implementation of ReadThread will help me.我无法弄清楚线程池的过载,任何关于 ReadThread 实现的建议都会对我有所帮助。

UPDATE 1 : java.lang.OutOfMemoryError on fixed thread pool更新 1:固定线程池上的 java.lang.OutOfMemoryError

Snippet of calling read event :调用读取事件的片段:

Thread per read:每次阅读的线程:

try {
    if (!key.isValid()) {
        continue;
    }
    if (key.isAcceptable()) {
        this.accept(key);
    }
    else if (key.isReadable()) {
        new Thread(new ReadEvent(key)).start();
    }
}
catch (CancelledKeyException e) {// key has been canceled
}

The above snippet works fine for few thousands of clients.上面的代码片段适用于几千个客户端。

Using Thread pool使用线程池

ExecutorService executor = Executors.newFixedThreadPool(100);

try {
    if (!key.isValid()) {
        continue;
    }
    if (key.isAcceptable()) {
        this.accept(key);
    }
    else if (key.isReadable()) {
        executor.execute(new ReadEvent(key));
    }
}
catch (CancelledKeyException e) {// key has been canceled
}

The above snippet doesn't serves all clients and found the heap size is increasing gradually and most(almost 100%) of the CPU is used for GC and finally got java.lang.OutOfMemoryError: GC overhead limit exceeded exception上面的代码片段没有为所有客户端提供服务,发现堆大小逐渐增加,大部分(几乎 100%)的 CPU 用于GC ,最终得到java.lang.OutOfMemoryError: GC 开销限制超出异常

6.7 years later but hey I had a similar issue. 6.7 年后,嘿,我遇到了类似的问题。 The problem is until the socket is actually read [socketChannel.read(...)] the operation is deemed as valid.问题是在实际读取套接字之前 [socketChannel.read(...)] 操作被认为是有效的。 By submitting the SelectionKey to the thread pool, remember that the thread will execute independently from the selecting thread meaning the operation is still ready as per the selecting thread and will keep submitting the operation to your thread pool until one of the submitted threads actually reads [socketChannel.read(...)] the channel and the operation is deemed as invalid and removed from the ready set.通过将 SelectionKey 提交到线程池,请记住该线程将独立于选择线程执行,这意味着该操作仍按照选择线程准备就绪,并将继续将操作提交到您的线程池,直到其中一个提交的线程实际读取 [ socketChannel.read(...)] 通道和操作被视为无效并从就绪集中删除。 Solution as mentioned by others already is read the bytes within the selecting thread and then pass the channel and the read contents into the thread pool for post processing.其他人已经提到的解决方案是读取选择线程内的字节,然后将通道和读取的内容传递到线程池中进行后期处理。

  case SelectionKey.OP_READ: {
       SocketChannel channel = (SocketChannel) key.channel();
       try {
            ByteBuffer buffer = ByteBuffer.allocate(1024 * 8);
            int read = channel.read(buffer);// read in selecting thread
            if (read <= -1) {
                key.cancel();//Signals the channel is closed
            } else {
               threadPool.execute(() -> {
                  //pass the channel & contents into the thread pool
               });
            }
       } catch (IOException e) {
           e.printStackTrace();
           key.cancel();
       }
  }
  break;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM