Java IO与NIO的区别

nio是new io的简称,从jdk1.4就被引入了。现在的jdk已经到了1.6了,可以说不是什么新东西了。但其中的一些思想值得我来研究。这两天,我研究了下其中的套接字部分,有一些心得,在此分享。 首先先分析下:为什么要nio套接字? nio的主要作用就是用来解决速度差异的。举个例子:计算机处理的速度,和用户按键盘的速度。这两者的速度相差悬殊。如果按照经典的方法:一个用户设定一个线程,专门等待用户的输入,无形中就造成了严重的资源浪费:每一个线程都需要珍贵的cpu时间片,由于速度差异造成了在这个交互线程中的cpu都用来等待。 nio套接字是怎么做到的? 其实,其中的思想很简单:轮询。一个线程轮询多个input;传统的方式是:有n个客户端就要有n个服务线程+一个监听线程,现在采取这种凡是,可以仅仅使用1个线程来代替n个服务线程以此来解决。 具体应用例子: 在ftp的控制连接中,因为只有少量的字符命令进行传输,所以可以考虑利用这种轮询的方式实现,以节省资源。 具体见例子。 Java代码
    package com.cxz.io;

    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.net.ServerSocket;
    import java.net.Socket;
    import java.util.HashMap;
    import java.util.Map;
    import java.util.Collections;

    public class IoEchoServer implements Runnable {

        // ThreadLocal<Socket> localSocket = new ThreadLocal<Socket>();
        Map<String, Socket> socketMap = Collections
                .synchronizedMap(new HashMap<String, Socket>());

        int threadCounter = 0;

        synchronized private int getCounter() {
            return threadCounter++;
        }

        public IoEchoServer() throws IOException {
            ServerSocket server = new ServerSocket(1984);
            while (true) {
                Socket socket = server.accept();
                // happened in the main thread.
                // localSocket.set(socket);
                String threadName = "---Thread" + getCounter() + "---";
                socketMap.put(threadName, socket);
                this.start(threadName);
            }
        }

        /**
         * @param args
         * @throws IOException
         */
        public static void main(String[] args) throws IOException {
            new IoEchoServer();
        }

        public void run() {
            try {
                Socket socket = socketMap.get(Thread.currentThread().getName());
                BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                //PrintWriter out = new PrintWriter(socket.getOutputStream());
                String buffer = null;
                while(!"END".equals(buffer)){
                    buffer = in.readLine();
                    System.out.println(buffer);
                }
                in.close();
                socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        public void start(String threadName) {
            new Thread(this, threadName).start();
        }

    }

 下面这个例子采取了nio方式实现,虽然还是有阻塞部分,但是与上一个相比,效率已经大幅提高。仅仅阻塞到一个监听线程中。 Java代码
    package com.cxz.nio;

    import java.io.IOException;
    import java.net.InetSocketAddress;
    import java.nio.ByteBuffer;
    import java.nio.CharBuffer;
    import java.nio.channels.SelectionKey;
    import java.nio.channels.Selector;
    import java.nio.channels.ServerSocketChannel;
    import java.nio.channels.SocketChannel;
    import java.nio.charset.Charset;
    import java.nio.charset.CharsetDecoder;
    import java.util.Iterator;
    import java.util.Set;

    public class NioEchoServer {

        private static Selector roller = null;

        private static final int port = 8080;

        private static NioEchoServer instance = null;

        private ThreadLocal<StringBuffer> stringLocal = new ThreadLocal<StringBuffer>();

        private NioEchoServer() throws IOException {
            ServerSocketChannel serverChannel = ServerSocketChannel.open();
            serverChannel.socket().bind(new InetSocketAddress(port));
            serverChannel.configureBlocking(false);
            serverChannel.register(roller, SelectionKey.OP_ACCEPT);
        }

        public synchronized static NioEchoServer getInstance() throws IOException {
            if (instance == null) {
                roller = Selector.open();
                instance = new NioEchoServer();
            }
            return instance;
        }

        public void start() throws IOException {
            int keyAdded = 0;
            while ((keyAdded = roller.select()) > 0) {
                Set<SelectionKey> keySets = roller.selectedKeys();
                Iterator iter = keySets.iterator();
                while (iter.hasNext()) {
                    SelectionKey key = (SelectionKey) iter.next();
                    iter.remove();
                    actionHandler(key);
                }
            }
        }

public void actionHandler(SelectionKey key) throws IOException {
            if (key.isAcceptable()) {
                ServerSocketChannel serverChannel = (ServerSocketChannel) key
                        .channel();
                SocketChannel socketChannel = serverChannel.accept();
                socketChannel.configureBlocking(false);
                socketChannel.register(roller, SelectionKey.OP_READ);
            } else if (key.isReadable()) {
                ByteBuffer buffer = ByteBuffer.allocate(16);
                SocketChannel socketChannel = (SocketChannel) key.channel();
                socketChannel.read(buffer);
                buffer.flip();
                String temp = decode(buffer);
                StringBuffer strBuffer = stringLocal.get();
                if (strBuffer == null) {
                    strBuffer = new StringBuffer();
                }

                strBuffer.append(temp);

                if (temp.equals("\r\n")) {
                    System.out.println(strBuffer.toString());
                    strBuffer = null;
                }
                stringLocal.set(strBuffer);
            }
        }

        public String decode(ByteBuffer buffer) {
            Charset charset = null;
            CharsetDecoder decoder = null;
            CharBuffer charBuffer = null;
            try {
                charset = Charset.forName("UTF-8");
                decoder = charset.newDecoder();
                charBuffer = decoder.decode(buffer);
                return charBuffer.toString();
            } catch (Exception ex) {
                ex.printStackTrace();
                return "";
            }
        }

        public static void main(String[] args) {
            try {
                NioEchoServer.getInstance().start();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }

你可能感兴趣的:(java,nio)