javaNIO学习笔记(四)JavaNIOSelector selector(选择器)作为JavaNIO的一个组件,它可以检查一个或多个JavaNIO通道实例,并确定哪些通道可以读取或写入。通过这种方式,一个线程可以管理多个通道,从而实现多个网络连接。因为是单线程处理多个通道的信息,因此用于处理通道数据的线程数就会减少,这样就可以节省下线程之间切换的时间成本。开启selector selector。open()注册selector channel。register() 将监听器register到非阻塞channel,并指定监听的事件,并得到一个SelectionKey实例。 通道必须处于非阻塞模式才能与选择器一起使用。这意味着你不能使用FileChannel的选择器,因为FileChannel的不能切换到非阻塞模式。 监听一般有四个事件 这四个事件由四个SelectionKey常量表示: SelectionKey。OPCONNECT SelectionKey。OPACCEPT:就是就绪 SelectionKey。OPREAD SelectionKey。OPWRITE 如果想监听多个事件可以按照如下方式写: intinterestSetSelectionKey。OPREADSelectionKey。OPWRITE; SelectionKey 一些常见方法返回SelectionKey的attachment,attachment可以在注册channel的时候指定。SelectionKey。attachment(object);SelectionKeykeychannel。register(selector,SelectionKey。OPREAD,theObject);返回该SelectionKey对应的channel。SelectionKey。channel();返回该SelectionKey对应的Selector。SelectionKey。selector();返回代表需要Selector监控的IO操作的bitmaskSelectionKey。interestOps();返回一个bitmask,代表在相应channel上可以进行的IO操作。SelectionKey。readyOps();创建ready集合的方法intreadySetselectionKey。readyOps();检查这些操作是否就绪的方法SelectionKey。isAcceptable();是否可读,是返回truebooleanisWritable():是否可写,是返回truebooleanisConnectable():是否可连接,是返回truebooleanisAcceptable():是否可接收,是返回true判断Selector是否对Channel的某种事件感兴趣intinterestSetselectionKey。interestOps();booleanisInterestedInAccept(interestSetSelectionKey。OPACCEPT)SelectionKey。OPACCEPT;booleanisInterestedInConnectinterestSetSelectionKey。OPCONNECT;booleanisInterestedInReadinterestSetSelectionKey。OPREAD;booleanisInterestedInWriteinterestSetSelectionKey。OPWRITE;Channelchannelkey。channel();Selectorselectorkey。selector(); select()方法:返回值表示有多少通道已经就绪,一旦调用select()方法,并且返回值不为0时,则可以通过调用Selector的selectedKeys()方法来访问已选择键集合。intselect():阻塞到至少有一个通道在你注册的事件上就绪了。intselect(longtimeout):和select()一样,但最长阻塞时间为timeout毫秒。intselectNow():非阻塞,只要有通道就绪就立刻返回。 选择器执行选择的过程,系统底层会依次询问每个通道是否已经就绪,这个过程可能会造成调用线程进入阻塞状态,那么我们有以下三种方式可以唤醒在select()方法中阻塞的线程。wakeup()方法:通过调用Selector对象的wakeup()方法让处在阻塞状态的select()方法立刻返回该方法使得选择器上的第一个还没有返回的选择操作立即返回。如果当前没有进行中的选择操作,那么下一次对select()方法的一次调用将立即返回。close()方法:通过close()方法关闭Selector该方法使得任何一个在选择操作中阻塞的线程都被唤醒(类似wakeup()),同时使得注册到该Selector的所有Channel被注销,所有的键将被取消,但是Channel本身并不会关闭。 下面的代码是参考文档中对应给出的。packagejniolearn。selector;importjava。io。IOException;importjava。net。InetSocketAddress;importjava。nio。channels。SelectionKey;importjava。nio。channels。Selector;importjava。nio。channels。ServerSocketChannel;importjava。util。Iterator;importjava。util。Set;Author:jimmyDate:202061522:15Description:publicclassSelectorPrc{publicstaticvoidmain(String〔〕args)throwsIOException{ServerSocketChannelsscServerSocketChannel。open();ssc。socket()。bind(newInetSocketAddress(localhost,8080));设置为非则色ssc。configureBlocking(false);开启一个选择器SelectorselectorSelector。open();注册选择器和监听的事件ssc。register(selector,SelectionKey。OPACCEPT);while(true){intreadyNumselector。select();if(readyNum0){continue;}SetSelectionKeyselectedKeysselector。selectedKeys();IteratorSelectionKeyitselectedKeys。iterator();while(it。hasNext()){SelectionKeykeyit。next();if(key。isAcceptable()){接受连接}elseif(key。isReadable()){通道可读}elseif(key。isWritable()){通道可写}keyIterator。remove()调用。选择器不会从所选键集本身移除SelectionKey实例。处理完通道时,必须这样做。下次通道变为ready时,选择器将再次将其添加到选中的键集。it。remove();}}}}JavaNIOPipe pipe的意思是管道,那么前面几篇学习中我说channel也可以理解为管道是错误的,这里更正下,channel应该理解为通道,防止概念混乱。 管道单项连接2给线程的。管道具有源通道和接收通道。将数据写入接收通道。然后可以从源通道读取该数据。packagejniolearn。channel;importjava。io。IOException;importjava。nio。ByteBuffer;importjava。nio。channels。Pipe;Author:jimmyDate:202061523:44Description:publicclassNioPipe{publicstaticvoidmain(String〔〕args)throwsIOException{开启pipePipepipePipe。open();接受通道开启Pipe。SinkChannelsinkChannelpipe。sink();准备数据StringnewDatajimmypipe;ByteBufferbufByteBuffer。allocate(48);buf。clear();buf。put(newData。getBytes());buf。flip();写入数据while(buf。hasRemaining()){sinkChannel。write(buf);}接受数据ByteBufferbufferByteBuffer。allocate(48);Pipe。SourceChannelsourceChannelpipe。source();intlensourceChannel。read(buffer);buffer。flip();System。out。println(newString(buffer。array(),0,len));4。关闭管道sinkChannel。close();sourceChannel。close();}}JavaNIOPath JDK7新增Path接口,Paths工具类,Files工具类。这些接口和工具类对NIO中的功能进行了高度封装,大大简化了文件系统的IO编程。 分别位于java。nio。file、java。nio。channels包下Path Path接口表示的是一个与平台无关的路径(文件和目录都用Path表示)。 Path类中包含了常用的操作路径的方法,getRoot()Path对象的跟路径toAbsolutePath()Path对象的绝对路径getNameCount()Path对象里包含的路径数量PathpathPaths。get(c:datamyfile。txt); 在Unix系统(Linux,MacOS,FreeBSD等)上,上面的绝对路径看起来像这样:PathPaths。get(homejakobjenkovmyfile。txt); Path接口的normalize()方法可以规范化路径StringoriginalPathd:dataprojectsaproject。。anotherproject;Pathpath1Paths。get(originalPath);System。out。println(path1path1);Pathpath2path1。normalize();System。out。println(path2path2);规范化路径不包含aproject。。部分,因为这是多余的。被删除的部分没有添加到最终的绝对路径。path1d:dataprojectsaproject。。anotherprojectpath2d:dataprojectsanotherprojectp1。toFile();Paths工具类 Paths工具类包含了两个返回Path对象的静态方法。staticPathget(URIuri)直接通过路径返回Path对象staticPathget(Stringfirst,Stringmore)通过给出的String字符串组装成一个Path对象packagejniolearn;importjava。nio。file。Path;importjava。nio。file。Paths;Author:jimmyDate:202061600:10Description:publicclassPathPrc{publicstaticvoidmain(String〔〕args){在传统java。io中,文件和目录都被抽象成File对象,即FilefilenewFile(。);NIO。2中则引入接口Path代表与平台无关的路径,文件和目录都用Path对象表示通过路径工具类Paths返回一个路径对象PathPathpathPaths。get(。);System。out。println(path里包含的路径数量:path。getNameCount());System。out。println(path的根路径:path。getRoot());path的绝对路径对比传统java。io,取绝对路径file。getAbsoluteFile()PathabsolutePathpath。toAbsolutePath();System。out。println(path的绝对路径:);System。out。println(absolutePath);System。out。println(absolutePath的根路径:absolutePath。getRoot());System。out。println(absolutePath里包含的路径数量:absolutePath。getNameCount());System。out。println(absolutePath。getName(3));以多个String来构建path》java。lang。IllegalArgumentException,路径不存在会报错Pathpath2Paths。get(D:,myProject,ThreadNotes);System。out。println(path2);}} 下一篇学习file和异步Channel。