目录
来由:最传统的模式中,一个线程,阻塞的完成独写任务,效率低下,于是就产生了经典的 "Connection per THread"模式,当一个任务触发的时候就派发给一个线程去处理,也就是一个线程对应一个socket,而且一个线程只能处理一个socket,因为独写是阻塞的,如果一个线程处理多个socket也是要排队的。那么就出现了大量的线程,线程的上下文切换是很消耗资源的。于是“Reactor"反应器模式诞生了!可以做到一个线程处理大量的连接。!
一,单线程Reactor反应器模式
Reactor反应器:负责查询IO事件,将就绪的IO事件发送给相应的Handler处理器进行处理。
Handler处理器:与IO事件进行绑定,负责IO事件的处理。完成真正的连接建立,业务处理,把结果写回通道等等功能。
什么是单线程Readctor反应器?
所有任务(selector,handler,channel)都处于同一个线程中,当selector.select()方法获得多个key的时候,使用while循环,一次提取一个key,抓取到对应的handler进行执行,然后while()直到key处理完毕。
class MyThread implements Runnable{
Selector selector;
ServerSocketChannel serverSocket;
MyThread() throws IOException{
serverSocket=ServerSocketChannel.open();
serverSocket.configureBlocking(false);
serverSocket.bind(new InetSocketAddress(8080));
selector=Selector.open();
SelectionKey sk=serverSocket.register(selector,SelectionKey.OP_ACCEPT);
//将 新连接 处理器 作为附件,绑定到Sk选择键。 ---重点!,此处new的handler。
sk.attach(new AcceptorHandler());
}
@Override
public void run() {
try {
while(!Thread.interrupted()) {
selector.select();
Set selected=selector.selectedKeys();
Iterator it=selected.iterator();
while(it.hasNext()) { //【重点】,线性执行,一次一个handler
SelectionKey sk=(SelectionKey)it.next();
dispath(sk);
}
}} catch (IOException e) {
e.printStackTrace();
}
}
private void dispath(SelectionKey sk) {
Runnable handler=(Runnable)(sk.attachment());
if(handler!=null) {
handler.run();
}
}
class AcceptorHandler implements Runnable{
public void run() {}
}
}
缺点:reactor和handler在同一个线程,那么当一个handler阻塞了,那么后面的handler也阻塞了,那么系统会崩溃。
二,多线程Reactor反应器模式
handler处理器:使用多线程,升级为线程池。比如多个线程来处理read操作,多个线程来吃力write操作。
进一步,还可以升级selector: 引入多个Selector选择器,提示选择大量通道能力。这里就和kafka的模式一样了。
class ServerReactor{
ServerSocketChannel serverSocket;
AtomicInteger next=new AtomicInteger(0);
Selector[]selectors=new Selector[2];
SubReactor[] subReactors=null;
ServerReactor() throws IOException{
//初始化 selector 选择器 【多个】
selectors[0]=Selector.open();
selectors[1]=Selector.open();
serverSocket=ServerSocketChannel.open();
InetSocketAddress address=new InetSocketAddress("127.0.0.1",8080);
serverSocket.socket().bind(address);
serverSocket.configureBlocking(false);
//第一个选择器,负责监控新连接事件
SelectionKey sk=serverSocket.register(selectors[0], SelectionKey.OP_ACCEPT);
//绑定 handler
sk.attach(new AcceptorHandler()); //--------》绑定handler。
//一个子反应器,负责一个选择器;
SubReactor sub1=new SubReactor(selectors[0]);
SubReactor sub2=new SubReactor(selectors[1]);
subReactors=new SubReactor[] {sub1,sub2};
}
private void startService() {
new Thread(subReactors[0]).start();
new Thread(subReactors[1]).start();
}
public static void main(String []args) throws IOException {
ServerReactor serverReactor=new ServerReactor();
serverReactor.startService();
}
class SubReactor implements Runnable{
//每个线程负责一个选择器的查询和选择。
private Selector selector;
public SubReactor(Selector selector) {
this.selector=selector;
}
public void run() {
try {
while(!Thread.interrupted()) {
selector.select();
Set<SelectionKey> KeySet=selector.selectedKeys();
Iterator<SelectionKey> it=KeySet.iterator();
while(it.hasNext()) {
SelectionKey sk=it.next();
dispatch(sk);
}
KeySet.clear();
}
}catch(Exception e) {
e.printStackTrace();
}
}
// handler的调用。入门;
public void dispatch(SelectionKey sk) {
Runnable handler=(Runnable) sk.attachment();
if(handler!=null)
handler.run();
}
}
class AcceptorHandler implements Runnable{
public void run() {
try {
SocketChannel channel=serverSocket.accept();
//----重点----这里才是多线程调用。
if(channel!=null)
new AHandler(selectors[next.get()],channel);
}catch(Exception e) {
e.printStackTrace();
}
if(next.incrementAndGet()==selectors.length)
next.set(0);
}
}
}
多线程handler处理器:
public class AHandler {
private SocketChannel channel;
private SelectionKey sk;
private ByteBuffer byteBuffer =ByteBuffer.allocate(1024);
static ExecutorService pool=Executors.newFixedThreadPool(4);
static final int RECIEVING=0,SENGDING=1;
int state =RECIEVING;
AHandler(Selector selector,SocketChannel c) throws IOException{
channel=c;
c.configureBlocking(false);
sk=channel.register(selector, 0);
sk.attach(this);// 向sk选择键 注册read就绪事件。-------连接事件注册为 可读事件!
sk.interestOps(SelectionKey.OP_READ);
selector.wakeup();
}
public void run() {
pool.execute(new AsyncTask());
}
public synchronized void asyncRun() {
try {
if(state ==SENGDING) {
channel.write(byteBuffer);//写入; 写/对应读取。
byteBuffer.clear();//转换为写入模式。
sk.interestOps(SelectionKey.OP_READ);
state=RECIEVING;//转换为接收状态。
}else if(state==RECIEVING) {
int length=0;
while((length=channel.read(byteBuffer))>0)
System.out.println(new String(byteBuffer.array(),0,length));
byteBuffer.flip();
sk.interestOps(SelectionKey.OP_WRITE);
state=SENGDING;//状态转换。
}
}catch(Exception e) {
e.printStackTrace();
}
}
class AsyncTask implements Runnable{
public void run() {
AHandler.this.asyncRun();
}
}
}