粗暴的解释程序员
从JDK 1.0开始,用户就能够经过Socket进行网络编程。在JDK 1.4后,又提供了一种全新的编程方式。编程
在翻阅文档的时候,相信很多人对“多路复用”这个词感到陌生和费解。服务器
对于程序员来讲,代码是更容易理解。网络
BIO示例:多线程
ExecutorService executor = Excutors.newFixedThreadPollExecutor(100);//创建线程池 ServerSocket serverSocket = new ServerSocket();//新建Socket serverSocket.bind(8088);//监听8088端口 while(!Thread.currentThread.isInturrupted()){ Socket socket = serverSocket.accept();//循环等待新链接进入 executor.submit(new ConnectIOnHandler(socket));//放入线程池中处理读写任务 } class ConnectIOnHandler extends Thread{ private Socket socket; public ConnectIOnHandler(Socket socket){ this.socket = socket; } public void run(){ while(!Thread.currentThread.isInturrupted()&&!socket.isClosed()){ String someThing = socket.read();//读取对方发来的消息 if(someThing!=null){ //TODO 作业务处理 socket.write();//返回结果 } } } }
NIO 示例:并发
class IoThread extends Thread{ public void run(){ Set<SelectionKey> selectedKeys= selector.selectedKeys(); //循环获取网络事件。 Iterator<SelectionKey> i = selectedKeys.iterator(); for (;;) { final SelectionKey k = i.next(); final Object a = k.attachment(); i.remove(); if (a instanceof AbstractNioChannel) { processSelectedKey(k, (AbstractNioChannel) a); } }
代码分析socket
在OIO中,将新链接放入到线程池中,利用多线程处理实际的读写任务。其中Socket的accept、read、write皆为阻塞操做。能够简单的认为每个Socket链接对应了操做系统的一个小文件,对Socket的读写就是对这个文件的读写。这是一路一线程,或者是多路一线程的概念。性能
而在NIO中,经过Selector将Channel和event统一管理了起来。一次selector操做能够获取一个或者多个网络链接中的读写事件。这即是是多路复用的由来,它能够同时对多个网络链接进行操做。this
为什么引入NIO操作系统
在OIO编程模式中,经过线程池的引入,解决了OIO阻塞而引起的并行效率问题。看似已经美好,可是互联网的发展和用户量的提高,这种古老的编程模式遭受了挑战。
在OIO中,很难提高并发量。每个新链接都须要一个Socket对象,虽然共用了线程池,可是为了保证响应性,须要设置较大的线程数。因为线程资源自己昂贵,过量的线程又会致使CPU资源竞争激烈,下降服务性能。OIO的特性决定了它必然没法支撑较大的并发量。
在NIO中,经过多路复用机制,解决了须要很是多的线程专一IO读写的问题,下降了服务的负载。从而提高了服务器的并发量。
多路复用使得服务的并发性上升了一个台阶,进一步的提高还有一个挑战。下一章将对此进行详细阐述。