• JavaIO和JavaNIO


    BIO和NIO

    BIO在之前的服务器处理模型中,在调用ServerSocket.accept()方法时,会一直阻塞到有客户端连接才会返回,每个客户端连接过来后,服务端都会accept一个新连接,接着启动一个线程去处理该客户端的请求。在这个新的线程中,也会在read()方法中阻塞,直到读取完数据,处理完成后销毁该处理线程。

    这样会有什么问题呢?

    当客户端并发访问增加后,服务端线程个数膨胀,频繁出现由于IO阻塞导致挂起的线程,系统性能将急剧下降,容易发生线程堆栈溢出、创建新线程失败等问题。

    阻塞导致大量线程资源被浪费;阻塞可导致大量的上下文切换,很多切换其实是无意义的

    Java自1.4以后,加入了新IO特性NIO,NIO带来了non-blocking特性。

    那么NIO是如何帮助我们解决这种问题的呢(反应器设计模式)?

    1). 由一个专门的线程来处理所有的 IO 事件,并负责分发。 
    2). 事件驱动机制:事件到的时候触发,而不是同步的去监视事件。 
    3). 线程通讯:线程之间通过 wait,notify 等方式通讯。保证每次上下文切换都是有意义的。减少无谓的线程切换。 

    服务端和客户端各自维护一个管理通道的对象,我们称之为selector,该对象能检测一个或多个通道 (channel) 上的事件。我们以服务端为例,如果服务端的selector上注册了读事件,某时刻客户端给服务端发送了一些数据,NIO的服务端会在selector中添加一个读事件。服务端的处理线程会轮询地访问selector,如果访问selector时发现有感兴趣的事件到达,则处理这些事件,如果没有感兴趣的事件到达,则处理线程会一直阻塞直到感兴趣的事件到达为止。

    1、IO的例子

    /* 字节IO */
        public void byteIO() throws FileNotFoundException, IOException {
            FileInputStream fin = new FileInputStream(new File(
                    "D:\test\byteio_in.txt"));
            FileOutputStream fout = new FileOutputStream(new File(
                    "D:\test\byteio_out.txt"));
            int c = -1;
            while ((c = fin.read()) != -1) {
                fout.write(c);
            }
            fin.close();
            fout.close();
        }
    
        /* 字符IO */
        public void charIO() throws FileNotFoundException, IOException {
            FileReader reader = new FileReader(new File("D:\test\chario_in.txt",
                    ""));
            FileWriter writer = new FileWriter(new File("D:\test\chario_out.txt"));
            char[] charArr = new char[512];
            while (reader.read(charArr) != -1) {
                writer.write(charArr);
            }
            reader.close();
            writer.close();
        }
    
        /* bufferIO */
        public void bufferIO() throws FileNotFoundException, IOException {
            BufferedInputStream bufferReader = new BufferedInputStream(
                    new FileInputStream("D:\test\bufferio_in.txt"));
            BufferedOutputStream bufferWriter = new BufferedOutputStream(
                    new FileOutputStream("D:\test\bufferio_out.txt"));
            int c = -1;
            while ((c = bufferReader.read()) != -1) {
                bufferWriter.write(c);
            }
            bufferReader.close();
            bufferWriter.close();
        }

    2、NIO的例子

    /* NIO */
        public void NIO() throws FileNotFoundException, IOException {
            FileInputStream fin = new FileInputStream("D:\test\nio_in.txt");
            FileOutputStream fout = new FileOutputStream("D:\test\nio_out.txt");
            FileChannel finChannel = fin.getChannel();
            FileChannel foutChannel = fout.getChannel();
            ByteBuffer buffer = ByteBuffer.allocate(512);
            while (finChannel.read(buffer) != 1)//读到缓存
            {
                buffer.flip();//指针跳到缓存头
                foutChannel.write(buffer);
                buffer.clear();//重置缓冲区
            }
            fin.close();
            fout.close();
        }

    3、NIO实现非阻塞Server服务

    下面是一个NIO实现Server的例子

    public class MultiPortEcho {
        private int ports[];
        private ByteBuffer echoBuffer = ByteBuffer.allocate(1024);
    
        public MultiPortEcho(int ports[]) throws IOException {
            this.ports = ports;
            go();
        }
    
        private void go() throws IOException {
            // Create a new selector
            Selector selector = Selector.open();
    
            // Open a listener on each port, and register each one with the selector
            for (int i = 0; i < ports.length; ++i) {
                ServerSocketChannel ssc = ServerSocketChannel.open();
                ssc.configureBlocking(false);
                ServerSocket ss = ssc.socket();
                InetSocketAddress address = new InetSocketAddress(ports[i]);
                ss.bind(address);
                SelectionKey key = ssc.register(selector, SelectionKey.OP_ACCEPT);
                System.out.println("Going to listen on " + ports[i]);
            }
    
            while (true) {
                int num = selector.select();
                Set selectedKeys = selector.selectedKeys();
                Iterator it = selectedKeys.iterator();
    
                while (it.hasNext()) {
                    SelectionKey key = (SelectionKey) it.next();
    
                    if ((key.readyOps() & SelectionKey.OP_ACCEPT) == SelectionKey.OP_ACCEPT) {
                        // Accept the new connection
                        ServerSocketChannel ssc = (ServerSocketChannel) key.channel();
                        SocketChannel sc = ssc.accept();
                        sc.configureBlocking(false);
    
                        // Add the new connection to the selector
                        SelectionKey newKey = sc.register(selector,SelectionKey.OP_READ);
                        it.remove();
    
                        System.out.println("Got connection from " + sc);
                    } else if ((key.readyOps() & SelectionKey.OP_READ) == SelectionKey.OP_READ) {
                        // Read the data
                        SocketChannel sc = (SocketChannel) key.channel();
    
                        // Echo data
                        int bytesEchoed = 0;
                        while (true) {
                            echoBuffer.clear();
                            int r = sc.read(echoBuffer);
                            if (r <= 0) {
                                break;
                            }
                            echoBuffer.flip();
                            sc.write(echoBuffer);
                            bytesEchoed += r;
                        }
    
                        System.out.println("Echoed " + bytesEchoed + " from " + sc);
                        it.remove();
                    }
    
                }
            }
        }
    
        static public void main(String args[]) throws Exception {
    
            int ports[] = {1234,6765,7987};
    
            for (int i = 0; i < args.length; ++i) {
                ports[i] = Integer.parseInt(args[i]);
            }
    
            new MultiPortEcho(ports);
        }
    }

     参考资料:

    http://www.ibm.com/developerworks/cn/education/java/j-nio/j-nio.html#ibm-pcon

    http://weixiaolu.iteye.com/blog/1479656

  • 相关阅读:
    JavaScript与C# Windows应用程序交互
    用DateTime.ToString(string format)输出不同格式的日期
    时间间隔与暂停
    C#中比较两个时间的时间差
    lambda函数的用法
    Tornado笔记
    DjangoWeb应用开发实战笔记
    再看装饰器
    描述符
    flask简单代码回顾
  • 原文地址:https://www.cnblogs.com/mingziday/p/4992998.html
Copyright © 2020-2023  润新知