java nio空轮循_Netty笔记-JavaNIO的空轮询Bug及Netty应对
时间: 2024-04-22 19:23:09 浏览: 332
好的,关于 Java NIO 空轮询问题,其实是在 NIO 的 Selector 中存在的一个 Bug。当 Selector 中没有任何待处理的事件时,Selector.select() 方法会一直阻塞,导致 CPU 资源的浪费。这个问题也被称为“空轮询”。
为了解决这个问题,Netty 使用了一种名为“被动轮询”的方式。在 Netty 中,Channel 的事件会被注册到一个 EventLoop 中,而不是直接注册到 Selector 中。当 Selector 中没有待处理的事件时,EventLoop 会等待一段时间,然后再次检查是否有事件需要处理。这样就避免了 Selector.select() 方法的空轮询问题。
除此之外,Netty 还提供了一些优化方式,如使用 Epoll 模型,减少 Selector 的创建和销毁等,来进一步提升性能和避免空轮询的问题。
希望我的回答能够解决您的问题。
相关问题
用 Java Nio 实现一个和Netty一样的功能Server端和client端
要实现一个和Netty一样的功能Server端和client端,可以使用Java NIO来进行实现。下面是一个简单的示例代码:
### Server端
```java
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;
public class NioServer {
private Selector selector;
private ByteBuffer readBuffer = ByteBuffer.allocate(1024);
private ByteBuffer writeBuffer = ByteBuffer.allocate(1024);
public NioServer(int port) {
try {
// 创建ServerSocketChannel对象并绑定端口
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.socket().bind(new InetSocketAddress(port));
serverSocketChannel.configureBlocking(false);
// 创建Selector对象
selector = Selector.open();
// 将ServerSocketChannel注册到Selector上,并设置为监听OP_ACCEPT事件
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
System.out.println("Server started, listening on port " + port);
} catch (IOException e) {
e.printStackTrace();
System.exit(1);
}
}
public void start() {
try {
while (true) {
// 阻塞等待事件的发生
selector.select();
// 获取发生事件的SelectionKey集合
Set<SelectionKey> selectionKeys = selector.selectedKeys();
Iterator<SelectionKey> iterator = selectionKeys.iterator();
while (iterator.hasNext()) {
SelectionKey selectionKey = iterator.next();
iterator.remove();
if (selectionKey.isAcceptable()) {
// ServerSocketChannel可以接收客户端连接
ServerSocketChannel serverSocketChannel = (ServerSocketChannel) selectionKey.channel();
SocketChannel socketChannel = serverSocketChannel.accept();
socketChannel.configureBlocking(false);
socketChannel.register(selector, SelectionKey.OP_READ);
System.out.println("Client " + socketChannel.getRemoteAddress() + " connected.");
} else if (selectionKey.isReadable()) {
// SocketChannel可以读取数据
SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
readBuffer.clear();
int numRead = socketChannel.read(readBuffer);
if (numRead == -1) {
// 客户端关闭连接
selectionKey.cancel();
socketChannel.close();
System.out.println("Client " + socketChannel.getRemoteAddress() + " disconnected.");
} else {
// 处理读取到的数据
String request = new String(readBuffer.array(), 0, numRead);
System.out.println("Received request from client " + socketChannel.getRemoteAddress() + ": " + request);
socketChannel.register(selector, SelectionKey.OP_WRITE);
}
} else if (selectionKey.isWritable()) {
// SocketChannel可以写入数据
SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
writeBuffer.clear();
String response = "Hello from server!";
writeBuffer.put(response.getBytes());
writeBuffer.flip();
socketChannel.write(writeBuffer);
socketChannel.register(selector, SelectionKey.OP_READ);
}
}
}
} catch (IOException e) {
e.printStackTrace();
System.exit(1);
}
}
public static void main(String[] args) {
NioServer server = new NioServer(8888);
server.start();
}
}
```
### Client端
```java
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;
public class NioClient {
private Selector selector;
private ByteBuffer readBuffer = ByteBuffer.allocate(1024);
private ByteBuffer writeBuffer = ByteBuffer.allocate(1024);
public NioClient(String host, int port) {
try {
// 创建SocketChannel对象并连接服务器
SocketChannel socketChannel = SocketChannel.open();
socketChannel.configureBlocking(false);
socketChannel.connect(new InetSocketAddress(host, port));
// 创建Selector对象
selector = Selector.open();
// 将SocketChannel注册到Selector上,并设置为监听OP_CONNECT事件
socketChannel.register(selector, SelectionKey.OP_CONNECT);
System.out.println("Connecting to server " + host + ":" + port);
} catch (IOException e) {
e.printStackTrace();
System.exit(1);
}
}
public void start() {
try {
while (true) {
// 阻塞等待事件的发生
selector.select();
// 获取发生事件的SelectionKey集合
Set<SelectionKey> selectionKeys = selector.selectedKeys();
Iterator<SelectionKey> iterator = selectionKeys.iterator();
while (iterator.hasNext()) {
SelectionKey selectionKey = iterator.next();
iterator.remove();
if (selectionKey.isConnectable()) {
// SocketChannel已连接到服务器
SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
if (socketChannel.isConnectionPending()) {
socketChannel.finishConnect();
}
socketChannel.configureBlocking(false);
socketChannel.register(selector, SelectionKey.OP_WRITE);
System.out.println("Connected to server " + socketChannel.getRemoteAddress());
} else if (selectionKey.isReadable()) {
// SocketChannel可以读取数据
SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
readBuffer.clear();
int numRead = socketChannel.read(readBuffer);
if (numRead == -1) {
// 服务器关闭连接
selectionKey.cancel();
socketChannel.close();
System.out.println("Server " + socketChannel.getRemoteAddress() + " disconnected.");
} else {
// 处理读取到的数据
String response = new String(readBuffer.array(), 0, numRead);
System.out.println("Received response from server " + socketChannel.getRemoteAddress() + ": " + response);
socketChannel.register(selector, SelectionKey.OP_WRITE);
}
} else if (selectionKey.isWritable()) {
// SocketChannel可以写入数据
SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
writeBuffer.clear();
String request = "Hello from client!";
writeBuffer.put(request.getBytes());
writeBuffer.flip();
socketChannel.write(writeBuffer);
socketChannel.register(selector, SelectionKey.OP_READ);
}
}
}
} catch (IOException e) {
e.printStackTrace();
System.exit(1);
}
}
public static void main(String[] args) {
NioClient client = new NioClient("localhost", 8888);
client.start();
}
}
```
这个示例代码实现了一个简单的NIO Server和Client,可以接收客户端连接,读取客户端发送的数据,并回复一条消息。虽然它没有Netty那么强大,但是可以作为一个参考来了解Java NIO的基本原理和使用方法。
java netty nio
Java BIO是一种传统的Java IO编程方式,采用同步阻塞的方式进行数据传输。在BIO模式下,服务器为每个连接启动一个线程进行处理,如果连接处于空闲状态,会造成不必要的线程开销。BIO适用于连接数较小且固定的架构,对服务器资源要求较高,且并发性受限。在JDK1.4之前,BIO是唯一的选择,因为其编程简单易理解。
Netty是一个开源的Java网络通信框架,它提供了异步非阻塞的网络编程模型。与BIO不同,Netty采用NIO模型进行实现,可以高效地处理大量的并发连接。Netty提供了更高级的抽象和功能,使开发人员能够更轻松地构建可扩展和高性能的网络应用程序。
阅读全文