单线程阻塞
ServerSocket serverSocket = new ServerSocket(7788);
while (true) {
Socket socket = serverSocket.accept();
handle(socket);
}
连接数:线程数 = n:1
优势:最简单的服务器模型,只有一个线程,开销小
劣势:只能串行处理
多线程阻塞
public static void main(String[] args) {
ServerSocket serverSocket = new ServerSocket(7788);
while (true) {
Socket socket = serverSocket.accept();
Thread t = new Thread(new Handle(socket));
t.start();
}
}
连接数:线程数 = 1:1
优势:支持并发处理
劣势:开销大;如果大量的线程都处在等待状态,浪费资源
多线程阻塞(线程池)
连接数:线程数 = n:m
单Reactor单线程
// 创建选择器
Selector selector = Selector.open();
// 非阻塞模式
channel.configureBlocking(false);
// 注册通道,关注读事件
SelectionKey selectionKey = channel.register(selector, SelectionKey.OP_READ);
while (true) {
// select()方法返回的int值表示有多少通道已经就绪
int readyChannels = selector.select();
if (readyChannels == 0) {
continue;
}
// 访问所有的已就绪的通道
Set<SelectionKey> selectedKeys = selector.selectedKeys();
Iterator keyIterator = selectedKeys.iterator();
while (keyIterator.hasNext()) {
SelectionKey key = (SelectionKey) keyIterator.next();
if (key.isAcceptable()) {
} else if (key.isConnectable()) {
} else if (key.isReadable()) {
} else if (key.isWritable()) {
}
// Selector不会自动从集合中移除key实例。必须在处理完通道时自己移除
// 下次该通道变成就绪时,Selector会再次将其放入已选择键集中
keyIterator.remove();
}
}
原理图:
说明:当客户端往套接字发送数据时,内核层从网卡接收数据后会调用回调函数,然后维护一个事件列表,应用层获取这个列表即可得到所有感兴趣的事件。
模型图:
优势:用一个线程就可实现对多个连接的管理,不会因为某个连接阻塞导致其他连接无法处理,提高了服务器的执行效率。
单Reactor多线程
将最耗时的业务逻辑处理交给线程池处理。
主从Reactor多线程
优势:充分利用服务器的多核,并发处理能力更高。