线程在处理数据时,若是线程还处于将数据从channel读到buffer的这段时间内,线程能够去作别的事情,等数据都读到buffer了,线程再回来处理读到的数据html
类比流的概念。与流的区别在于java
流的读取或写通常是一次性的操做,数据在读取过程当中不会有缓存,这也就意味着没有办法本身随便移动到想要读取的位置,要实现这个功能也就只能先缓存
FileChannel的write()方法不保证一次会写到channel中的字节数;另外它不能被设置为非阻塞,永远只能设置成阻塞模式
非阻塞模式下,等待链接到来的accept方法会立马返回,注意判断SocketChannel是否是null;另外可能有多个链接创建,因此监听通常会放在一个while循环里面
用来方便操做内存块中数据的一个包装类。它有3个属性数组
从写模式转换到读模式须要用flip()完成,调用完成以后,limit会被设置成position当时的值,而positon会被设置成0;读取数据完毕转换成写须要调用clear或者compact方法,其中clear会置position为0,limit为capacity,compact则会把原有的数据拷贝到开始的位置,而后其后的位置设置为position,limit则是capacity缓存
mark和reset用法:在执行读取的时候,先mark住当前的位置,执行读取完成以后reset就回到原读取数据以前的位置了网络
建立一个数组用来放要写的数据,或者将要读到的数据,再执行读写操做便可,可是这种方式不适合读取变长消息异步
Buffer[] bArr = {head,body}; channel.read(bArr); //读 ,若是head自己会放自身容量的数据而后再往body中塞 Buffer[] wArr={head,body} channel.write(wArr);//写
用来监控多个channel的事件,好比channel的链接创建、数据到达等等socket
实际上能够只用一个线程来管理全部的channel
//建立selector Selector selector = Selector.open(); //使用Selector必须设置为false,同时意味着FileChannel是不能用Selector channel.configureBlocking(false); // SelectionKey一共有4种值,分别表明4个事件:connect、accept、read、write // 经过方法 interestOps 能够获得注册时对channel感兴趣的事件,具体获取方式为 interestSet & SelectionKey.OP_ACCEPT 获得的结果便是否为ACCEPT事件 //经过这种方式即实现了注册,代表当前channel须要监听的是 read 事件,若是对多个事件感兴趣,那么可使用 SelectionKey.OP_READ | SelectionKey.OP_WRITE 方式实现 //注册方法还能够添加另外一个参数,attach,用来附加更多的信息给channel,好比将Buffer给channel SelectionKey key = channel.register(selector, SelectionKey.OP_READ); while(true) { //select()对channel注册的事件若是一个都没有好,那么阻塞住,返回值表示事件已经发生的chanel的个数; //selectNow()则不阻塞,没有准备好就返回0 int readyChannels = selector.select(); if(readyChannels == 0) continue; //用来获取准备好的channel Set<SelectionKey> selectedKeys = selector.selectedKeys(); Iterator<SelectionKey> keyIterator = selectedKeys.iterator(); while(keyIterator.hasNext()) { SelectionKey key = keyIterator.next(); if(key.isAcceptable()) { //SeverSocketChannel接受了一个新的链接 } else if (key.isConnectable()) { //和远程已经创建了链接 } else if (key.isReadable()) { //channel可读 } else if (key.isWritable()) { //channel可写 } //必须手动执行 keyIterator.remove(); } }
wakeup:若是channel当前恰好阻塞在select,会立马返回