阻塞与非阻塞
- 传统的IO流都是阻塞式的。也就是说,当一个线程调用read()或write()时,该线程被阻塞,直到有一些数据被读取或写入,改线程在此期间不能执行其他任务。因此,在完成网络通信进行IO操作时,由于线程会阻塞,所以服务端必须为每个客户端都提供一个独立的线程进行处理,当服务器端需要处理大量的客户端时,性能急剧下降。
在采用多线程进行读写的时候,每个客户端会有一条线程,并发量大的时候效率不高,且有可能在阻塞状态下永远拿不到缺失执行的资源,线程没有死掉,极大浪费CPU资源。
- Java NIO 是非阻塞模式的。当线程从某通道进行读写数据时,若没有数据可用时,该线程可以执行其他任务。线程通常将非阻塞IO的空闲时间用于在其通道上执行IO操作,所以单独的线程可以管理多个输入和输出通道。因此,在NIO可以让服务器使用一个或有限几个线程来同时处理连接到服务器端的所有客户端。
在客户端和和服务端建立了Channel和Selector,每一个Channel都要在Selector上注册,Selector会对所有注册的Channel进行监测,只有Channel的传输到服务端的数据都准备完成之后,Selector才去开启一个或者多个服务端线程执行Client端的网络IO操作。
选择器(Selector)
- 选择器(Selector)是SlectableChannel 对象的多路复用器,==Selector可以同时监控多个SelectableChannel 的 IO 状况 也就是说,利用Selector可使一个单独的线程管理多个Channel。Selector是非阻塞的IO的核心。
- SelectableChannel 的结构如下图:
选择器(Selector)的应用
- 创建Selector : 通过调用Selector.open() 方法创建一个Selector。
Selector selector = Selector.open();
- 向选择器注册通道:SelectableChannel.register( Selector sel, int ops)
Socket socket = new Socket(InetAddress.getByName("127.0.0.1"),9898);
SocketChannel channel = socket.getChannel();
Selector selector