NIO线程模型
Reactor 是什么
1.事件驱动(event handling)
2.可以处理一个或多个输入源(one or more inputs)
3.通过Service Handler同步的将输入事件(Event)采用多路复用分发给相应的Request Handler(多个)处理
三大核心角色:Reactor Acceptor Handler
Reactor:监听事件的发生,并分发给对应的handler处理,或者分发给acceptor
Acceptor: 处理客户端建立连接事件,并创建handler
Handler:处理后续的读写事件
这里分为:单线程Reactor模型、多线程Reactor模型、主从Reactor模型
1) 单线程Reactor模型
2)多线程Reactor模型
提高handler的处理效率,首先handler不再负责具体的业务逻辑,当读取出数据后,分发给子线程处理,子线程处理完成后再将结果返回给handler,handler再将结果返回给客户端
3)主从Reactor模型
mainReactor用来接收连接事件,然后分发给acceptor,acceptor在处理过程中,直接将后续的读写事件,注册到slaveReactor之中,以此来达到分流
代码实现
1)单线程实现
public class ReactorServer {
/**
* 对应角色为Reactor 反应器,通知器,监听器
*/
private Selector selector;
private ServerSocketChannel serverChannel;
public ReactorServer() {
try {
selector = Selector.open();
serverChannel = ServerSocketChannel.open();
//非阻塞
serverChannel.configureBlocking(false);
//端口设置为8888
SocketAddress address = new InetSocketAddress(8888);
serverChannel.socket().bind(address);
//注册连接事件的同时声明一个Acceptor和事件绑定
SelectionKey key = serverChannel.register(selector, SelectionKey.OP_ACCEPT);
//创建一个Acceptor放入SelectionKey中
Acceptor acceptor = new Acceptor(serverChannel, selector);
// Acceptor作为一个附加对象进行绑定
key.attach(acceptor);
while (true) {
int num = selector.select();
if (num == 0) {
continue;
}
// 获取要处理事件的集合
Set<SelectionKey> set = selector.selectedKeys();
Iterator<SelectionKey> iterator = set.iterator();
while (iterator.hasNext()){
SelectionKey selectionKey = iterator.next();
//避免重复处理
iterator.remove();
/**
* 拿到之前存储的附加对象
* 如果事件是接收事件分发给绑定的acceptor
* 如果事件是读写事件 分发给绑定的handler
*/
Runnable runnable = (Runnable)selectionKey.attachment();
runnable.run();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
public class Acceptor implements Runnable {
private ServerSocketChannel serverChannel;
private Selector selector;
public Acceptor(ServerSocketChannel serverChannel, Selector selector) {
this.serverChannel = serverChannel;
this.selector = selector;
}
@Override
public void run() {
try {
SocketChannel socketChannel = serverChannel.accept();
socketChannel.configureBlocking(false);
SelectionKey key = socketChannel.register(selector, SelectionKey.OP_READ);
// 创建handler用于处理后续的读写事件
Handler handler = new Handler(key);
// MultiHandler handler = new MultiHandler(key);
key.attach(handler);
// 唤醒阻塞
selector.wakeup();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public class Handler implements Runnable {
private SelectionKey key;
private State state;
public Handler(SelectionKey key) {
this.key = key;
this.state = State.READ;
}
@Override
public void run() {
//读执行读,写就执行写
switch (state) {
case READ:
read();
break;
case WRITE:
write();
break;
}
}
/**
* 读
*/
private void read() {
ByteBuffer buffer = ByteBuffer.allocate(1024);
try {
SocketChannel channel = (SocketChannel) key.channel();
int num = channel.read(buffer);
String msg = new String(buffer.array());
//读完关心状态写
key.interestOps(SelectionKey.OP_WRITE);
//切换状态
this.state = State.WRITE;
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 写
*/
private void write() {
ByteBuffer buffer = ByteBuffer.wrap("hello".getBytes());
try {
SocketChannel channel = (SocketChannel) key.channel();
channel.write(buffer);
//写完关心状态读
key.interestOps(SelectionKey.OP_READ);
//切换状态
this.state = State.READ;
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 读和写(两种状态)
*/
private enum State {
READ, WRITE
}
}
2)实现加入多线程
public class MultiHandler implements Runnable {
private SelectionKey key;
private State state;
private ExecutorService pool;
public MultiHandler(SelectionKey key) {
this.key = key;
this.state = State.READ;
}
@Override
public void run() {
switch (state) {
case READ:
//将耗时操作放在线程池中执行
pool.execute(() -> {
read();
});
break;
case WRITE:
write();
break;
}
}
/**
* 读
*/
private void read() {
ByteBuffer buffer = ByteBuffer.allocate(1024);
try {
SocketChannel channel = (SocketChannel) key.channel();
int num = channel.read(buffer);
String msg = new String(buffer.array());
key.interestOps(SelectionKey.OP_WRITE);
this.state = State.WRITE;
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 写
*/
private void write() {
ByteBuffer buffer = ByteBuffer.wrap("hello".getBytes());
try {
SocketChannel channel = (SocketChannel) key.channel();
channel.write(buffer);
key.interestOps(SelectionKey.OP_READ);
this.state = State.READ;
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 读和写(两种状态)
*/
private enum State {
READ, WRITE
}
}
3)加入主从实现
public class MultiReactorServer {
/**
* 对应角色为Reactor 反应器,通知器,监听器
*/
private Selector mainSelector;
/**
* 从Selector
*/
private Selector slaveSelector;
private ServerSocketChannel serverChannel;
public MultiReactorServer() {
try {
mainSelector = Selector.open();
//初始化从Selector
slaveSelector = Selector.open();
serverChannel = ServerSocketChannel.open();
serverChannel.configureBlocking(false);
SocketAddress address = new InetSocketAddress(8888);
serverChannel.socket().bind(address);
//注册连接事件的同时声明一个Acceptor和事件绑定
SelectionKey key = serverChannel.register(mainSelector, SelectionKey.OP_ACCEPT);
//创建一个Acceptor放入SelectionKey中
Acceptor acceptor = new Acceptor(serverChannel, slaveSelector);
// Acceptor作为一个附加对象进行绑定
key.attach(acceptor);
// 从Selector使用独立的线程监听事件,避免相互阻塞
new HandlerLoop(slaveSelector).run();
while (true) {
int num = mainSelector.select();
if (num == 0) {
continue;
}
// 获取要处理事件的集合
Set<SelectionKey> set = mainSelector.selectedKeys();
Iterator<SelectionKey> iterator = set.iterator();
while (iterator.hasNext()) {
SelectionKey selectionKey = iterator.next();
//避免重复处理
iterator.remove();
/**
* 拿到之前存储的附加对象
* 如果事件是接收事件分发给绑定的acceptor
* 如果事件是读写事件 分发给绑定的handler
*/
Runnable runnable = (Runnable) selectionKey.attachment();
runnable.run();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
public class HandlerLoop implements Runnable {
private Selector selector;
public HandlerLoop(Selector selector) {
this.selector = selector;
}
@Override
public void run() {
while (!Thread.interrupted()) {
try {
int select = selector.select();
if (select != 0) {
Set<SelectionKey> readKeys = selector.selectedKeys();
Iterator<SelectionKey> iterator = readKeys.iterator();
while (iterator.hasNext()) {
SelectionKey key = iterator.next();
Runnable runnable = (Runnable) key.attachment();
runnable.run();
iterator.remove();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}