NIO多路复用模式中,用户线程在读写前可以不用阻塞等待数据到来,交给selector去监控,那么它去干什么了?
1、用户线程如果不阻塞,继续往下走,那我的应用程序岂不是没有数据返回,那不就是返回null了?
2、很多帖子说nio释放了资源,用户线程可以做其它事情,那这样岂不是线程不安全的?
在多路复用IO模型中,会有一个线程(Java中的Selector)不断去轮询多个socket的状态,只有当socket真正有读写事件时,才真正调用实际的IO读写操作。因为在多路复用IO模型中,只需要使用一个线程就可以管理多个socket,系统不需要建立新的进程或者线程,也不必维护这些线程和进程,并且只有在真正有socket读写事件进行时,才会使用IO资源,所以它大大减少了资源占用。
什么是线程安全,这个要弄清楚,当多个线程访问某个方法时,不管你通过怎样的调用方式或者说这些线程如何交替的执行,我们在主程序中不需要去做任何的同步,这个类的结果行为都是我们设想的正确行为,那么我们就可以说这个类是线程安全的。
单线程模式肯定是线程安全的
那我们看看多线程的实现代码
public class Reactor implements Runnable { public final Selector selector; public final ServerSocketChannel serverSocketChannel; public Reactor(int port) throws IOException { //用于监控fds selector=Selector.open(); //socket服务器的chanel serverSocketChannel=ServerSocketChannel.open(); InetSocketAddress inetSocketAddress=new InetSocketAddress(InetAddress.getLocalHost(),port); // serverSocketChannel.socket().bind(inetSocketAddress); //不设置阻塞队列 serverSocketChannel.configureBlocking(false); //向selector注册该channel 返回selectionKey SelectionKey selectionKey=serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT); //利用selectionKey的attache功能绑定Acceptor 如果有事情,触发Acceptor selectionKey.attach(new Acceptor(this)); } public void run() { try { while(!Thread.interrupted()){ selector.select();//selector 阻塞 Set<SelectionKey> selectionKeys= selector.selectedKeys(); Iterator<SelectionKey> it=selectionKeys.iterator(); //Selector如果发现channel有OP_ACCEPT或READ事件发生,下列遍历就会进行。 while(it.hasNext()){ //来一个事件 第一次触发一个accepter线程 //以后触发SocketReadHandler SelectionKey selectionKey=it.next(); dispatch(selectionKey); selectionKeys.clear(); } } } catch (IOException e) { e.printStackTrace(); } } /** * 运行Acceptor或SocketReadHandler * @param key */ void dispatch(SelectionKey key) { Runnable r = (Runnable)(key.attachment()); if (r != null){ r.run(); } } }
运行结果不会受到这些线程如何交替的执行,而结果发生改变。
楼上的解答我理解,但是没有回答我的疑问,比如,我发送一个查询请求,那么通过NIO请求到服务端,这时候服务端需要用3秒处理。理论上在没有真正的读写时,客户端的用户线程是阻塞3秒等待服务端响应,还是交给selector监控,然后做别的事情了?