public static void main(String[] args) {
?
//创建一个buffer
ByteBuffer buffer = ByteBuffer.allocate(64);
?
for(int i = 0; i < 64; i++) {
buffer.put((byte)i);
}
?
//读取
buffer.flip();
?
//得到一个只读的Buffer
ByteBuffer readOnlyBuffer = buffer.asReadOnlyBuffer();
System.out.println(readOnlyBuffer.getClass());
?
//读取
while (readOnlyBuffer.hasRemaining()) {
System.out.println(readOnlyBuffer.get());
}
?
readOnlyBuffer.put((byte)100); //ReadOnlyBufferException
}
}
3)NIO 还提供了 MappedByteBuffer,可以让文件直接在内存(堆外的内存)中进行修改
public class MappedByteBufferTest {
public static void main(String[] args) throws Exception {
?
RandomaccessFile randomAccessFile = new RandomAccessFile("/Users/apple/学习/study/test01.txt", "rw");
//获取对应的通道
FileChannel channel = randomAccessFile.getChannel();
?
/**
* 参数1: FileChannel.MapMode.READ_WRITE 使用的读写模式
* 参数2: 0 : 可以直接修改的起始位置
* 参数3: 5: 是映射到内存的大小(不是索引位置) ,即将 1.txt 的多少个字节映射到内存
* 可以直接修改的范围就是 0-5
* 实际类型 DirectByteBuffer
*/
MappedByteBuffer mappedByteBuffer = channel.map(FileChannel.MapMode.READ_WRITE, 0, 5);
?
mappedByteBuffer.put(0, (byte) 'H');
mappedByteBuffer.put(3, (byte) '9');
// mappedByteBuffer.put(5, (byte) 'Y');//IndexOutOfBoundsException
?
randomAccessFile.close();
System.out.println("修改成功~~");
}
}
4)NIO 还支持 通过多个 Buffer (即 Buffer 数组) 完成读写操作,即 Scattering 和 Gathering
/**
* Scattering:将数据写入到buffer时,可以采用buffer数组,依次写入 [分散]
* Gathering: 从buffer读取数据时,可以采用buffer数组,依次读
*/
public class ScatteringAndGatheringTest {
public static void main(String[] args) throws Exception {
?
//使用 ServerSocketChannel 和 SocketChannel 网络
?
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
InetSocketAddress inetSocketAddress = new InetSocketAddress(7000);
?
//绑定端口到socket,并启动
serverSocketChannel.socket().bind(inetSocketAddress);
?
//创建buffer数组
ByteBuffer[] byteBuffers = new ByteBuffer[2];
byteBuffers[0] = ByteBuffer.allocate(5);
byteBuffers[1] = ByteBuffer.allocate(3);
?
//等客户端连接(telnet)
SocketChannel socketChannel = serverSocketChannel.accept();
//假定从客户端接收8个字节
int messageLength = 8;
//循环的读取
while (true) {
?
int byteRead = 0;
?
while (byteRead < messageLength) {
long l = socketChannel.read(byteBuffers);
//累计读取的字节数
byteRead += l;
System.out.println("byteRead=" + byteRead);
//使用流打印, 看看当前的这个buffer的position 和 limit
Arrays.stream(byteBuffers).map(buffer -> "position=" + buffer.position() + ", limit=" + buffer.limit()).forEach(System.out::println);
}
?
//将所有的buffer进行flip
Arrays.asList(byteBuffers).forEach(Buffer::flip);
?
//将数据读出显示到客户端
long byteWirte = 0;
while (byteWirte < messageLength) {
long l = socketChannel.write(byteBuffers);
byteWirte += l;
}
?
//将所有的buffer 进行clear
Arrays.asList(byteBuffers).forEach(Buffer::clear);
?
System.out.println("byteRead:=" + byteRead + " byteWrite=" + byteWirte + ", messageLength" + messageLength);
}
?
}
}
选择器(Selector)(1)基本介绍
1)Java的NIO,用非阻塞的IO方式 。可以用一个线程,处理多个的客户端连接,就会用到选择器
2)Selector能够检测多个注册的通道上是否有事件发生 。如果有事件发生,便获取事件然后针对每个事件进行相应的处理 。这样就可以只用一个单线程去管理多个通道,也就是管理多个连接和请求
3)只有在连接/通道真正有读写事件发生时,才会进行读写,就大大地减少了系统开销,并且不必为每个连接都创建一个线程,不用去维护多个线程
4)避免了多线程之间的上下文切换导致的开销
(2)常用方法

文章插图
(3)代码示例
NIOServer.java
public class NIOServer {
推荐阅读
- JavaEE编程基础:Servlet核心API用法详解
- Java生成随机图片验证码
- 13个需要知道的方法:使用 JavaScript 来操作 DOM
- 8个超实用的Java测试工具和框架
- java遍历文件的几种方法
- FF与IE对javascript和CSS的区别?
- Redis安装与使用之Java连接Redis
- java静态代理与动态代理
- Javascript中的8种常见数据结构
- 通过微信开放平台的UnionID机制用户数据互通
