NIO线程模型

分类专栏:
NIO相关

文章标签:
Java自学
NIO
原创

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

主从2


代码实现

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();
            }
        }
    }
}

以上图片来自我CSDN博客

  • 作者:潘震
  • 评论

    留言