基础---Reactor反应器模式

   

目录

一,单线程Reactor反应器模式

二,多线程Reactor反应器模式


来由:最传统的模式中,一个线程,阻塞的完成独写任务,效率低下,于是就产生了经典的 "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();
            }
      }
}

参考连接:https://www.jianshu.com/p/8a7519c8997d

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值