前言
高性能的Java通信,绝对离不开NIO组件,现在主流的技术框架或中间件服务器,都使用了Java NIO组件,譬如Tomcat、Jetty、Netty。 学习和掌握Java NIO组件,已经不是一项加分技能,而是一项必备技能。 不管是面试,还是实际开发,作为Java“攻城狮”(工程师的谐音),都必须掌握NIO的原理和开发实践技能。 本篇文章来简单介绍NIO的三大组件及其示例代码。
Channel
读写数据的双向通道
Buffer
Channel 将数据写入磁盘过程中的内存缓冲区
ByteBuffer 的基本使用
package com.pine.netty;
import java.io.FileInputStream;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
public class TestByteBuffer {
public static void main(String[] args) {
try (FileChannel fc = new FileInputStream("data.txt").getChannel()) {
// 创建 buffer
ByteBuffer buffer = ByteBuffer.allocate(10);
while (true) {
// 将数据从 channel 读出,并写到 buffer
int len = fc.read(buffer);
// 数据已读完
if (len <= 0) {
break;
}
// 切换到读模式
buffer.flip();
while (buffer.hasRemaining()) {
byte b = buffer.get();
System.out.println((char) b);
}
// 切换会写模式
buffer.clear();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
ByteBuffer 的空间分配
package com.pine.netty;
import java.nio.ByteBuffer;
public class TestByteBufferAllocate {
public static void main(String[] args) {
/**
* class java.nio.HeapByteBuffer
* 在 Java 堆内存中,读写效率低,受到 GC 的影响
*/
System.out.println(ByteBuffer.allocate(16).getClass());
/**
* class java.nio.DirectByteBuffer
* 在直接内存中,读写效率高,不受 GC 的影响,分配的效率低且容易导致内存泄漏
*/
System.out.println(ByteBuffer.allocateDirect(16).getClass());
}
}
selector
配合一个线程来管理多个 channel ,获取这些 channel 上发生的事件并交给线程执行
黏包和半包
package com.pine.netty;
import java.nio.ByteBuffer;
import static com.pine.netty.util.ByteBufferUtil.*;
public class TestByteBufferExam {
public static void main(String[] args) {
ByteBuffer buffer = ByteBuffer.allocate(32);
buffer.put("helloword\nI'mLihua\nho".getBytes());
split(buffer);
buffer.put("wareyou\n".getBytes());
split(buffer);
}
public static void split(ByteBuffer buffer) {
buffer.flip();
for (int i = 0; i < buffer.limit(); i++) {
byte curByte = buffer.get(i);
if (curByte == '\n') {
int length = i + 1 - buffer.position();
ByteBuffer buffer1 = ByteBuffer.allocate(length);
for (int j = 0; j < length; j++) {
buffer1.put(buffer.get());
}
debugAll(buffer1);
}
}
buffer.compact();
}
}
结语
本篇文章到这里就结束了,明天更新阻塞与非阻塞的内容,再见。