NIO多路复用模式中,用户线程在读写前可以不用阻塞等待数据到来,交给selector去监控,那么它去干什么了?
1、用户线程如果不阻塞,继续往下走,那我的应用程序岂不是没有数据返回,那不就是返回null了?
2、很多帖子说nio释放了资源,用户线程可以做其它事情,那这样岂不是线程不安全的?
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();
}
}
}
运行结果不会受到这些线程如何交替的执行,而结果发生改变。