java nio 模式原理学习

来源:互联网 发布:淘宝收货几天自动付款 编辑:程序博客网 时间:2024/05/21 08:55

 



  java nio 是指非阻塞io模式, 采用Reactor 模式实现及Observer模式。当IO通道中有数据进来的时候就会自动通知注册在通道的事件,然后找到对应的事件去执行。



看下面示例


      package com.yukh.nio.selector;  
      
    import java.io.IOException;  
    import java.net.InetAddress;  
    import java.net.InetSocketAddress;  
    import java.nio.channels.SelectionKey;  
    import java.nio.channels.Selector;  
    import java.nio.channels.ServerSocketChannel;  
    import java.nio.channels.SocketChannel;  
    import java.util.Iterator;  
    import java.util.Set;  
      
    import org.apache.log4j.Logger;  
      
    /**
     *      以下代码中巧妙使用了SocketChannel的attach功能,
     *将Hanlder和可能会发生事件的channel链接在一起,当发生事件时,
     *可以立即触发相应链接的Handler。
     */  
    public class Reactor implements Runnable {  
        public static Logger logger = Logger.getLogger(Reactor.class);  
        final Selector selector;  
        final ServerSocketChannel serverSocket;  
      
        Reactor(int port) throws IOException {  
            selector = Selector.open();                                 // 创建选择器  
            serverSocket = ServerSocketChannel.open();                  // 打开服务器套接字通道  
            InetSocketAddress address = new InetSocketAddress(InetAddress  
                    .getLocalHost(), port);  
            serverSocket.socket().bind(address);  
              
            serverSocket.configureBlocking(false);                      // 调整此通道的阻塞模式。 - 异步  
              
            SelectionKey sk = serverSocket.register(selector,           // 向selector注册该channel  
                    SelectionKey.OP_ACCEPT);                            // 用于套接字接受操作的操作集位。  
      
            logger.debug("-->Start serverSocket.register!");  
      
            // 利用sk的attache功能绑定Acceptor 如果有事情,触发Acceptor  
            sk.attach(new Acceptor());                                  // 将给定的对象附加到此键。  
            logger.debug("-->attach(new Acceptor()!");  
        }  
      
        public void run() { // normally in a new Thread  
            try {  
                while (!Thread.interrupted()) {  
                    selector.select();  
                    Set selected = selector.selectedKeys();  
                    Iterator it = selected.iterator();  
                    // Selector如果发现channel有OP_ACCEPT或READ事件发生,下列遍历就会进行。  
                    while (it.hasNext())  
                        // 来一个事件 第一次触发一个accepter线程  
                        // 以后触发SocketReadHandler  
                        dispatch((SelectionKey) (it.next()));  
                    selected.clear();  
                }  
            } catch (IOException ex) {  
                logger.debug("reactor stop!" + ex);  
            }  
        }  
      
        void dispatch(SelectionKey k) {  
            Runnable r = (Runnable) (k.attachment());  
            if (r != null) {  
                r.run();  
            }  
        }  
      
        class Acceptor implements Runnable {                                // inner  
            public void run() {  
                try {  
                    logger.debug("-->ready for accept!");  
                    SocketChannel c = serverSocket.accept();  
                    if (c != null)  
                        new SocketReadHandler(selector, c);                 // 调用Handler来处理channel  
                } catch (IOException ex) {  
                    logger.debug("accept stop!" + ex);  
                }  
            }  
        }  
    } 


处理类



    package com.yukh.nio.selector;  
      
    import java.io.IOException;  
    import java.nio.ByteBuffer;  
    import java.nio.channels.SelectionKey;  
    import java.nio.channels.Selector;  
    import java.nio.channels.SocketChannel;  
      
    import org.apache.log4j.Logger;  
      
    public class SocketReadHandler implements Runnable {  
        public static Logger logger = Logger.getLogger(SocketReadHandler.class);  
      
    //   private Test test=new Test();  
      
        final SocketChannel socket;  
        final SelectionKey sk;  
      
        static final int READING = 0, SENDING = 1;  
        int state = READING;  
      
        public SocketReadHandler(Selector sel, SocketChannel c) throws IOException {  
      
            socket = c;  
      
            socket.configureBlocking(false);  
            sk = socket.register(sel, 0);  
      
            // 将SelectionKey绑定为本Handler 下一步有事件触发时,将调用本类的run方法。  
            // 参看dispatch(SelectionKey k)  
            sk.attach(this);  
      
            // 同时将SelectionKey标记为可读,以便读取。  
            sk.interestOps(SelectionKey.OP_READ);  
            sel.wakeup();  
        }  
      
        public void run() {  
            try {  
                // test.read(socket,input);  
                readRequest();  
            } catch (Exception ex) {  
                logger.debug("readRequest error" + ex);  
            }  
        }  
      
        /**
         * 处理读取data
         *  
         * @param key
         * @throws Exception
         */  
        private void readRequest() throws Exception {  
      
            ByteBuffer input = ByteBuffer.allocate(1024);  
            input.clear();  
            try {  
      
                int bytesRead = socket.read(input);  
      
                // 激活线程池 处理这些request  
    //           requestHandle(new Request(socket,btt));  
      
            } catch (Exception e) {  
            }  
        }  
    }