NIO同步阻塞与同步非阻塞"/>
NIO同步阻塞与同步非阻塞
BIO与NIO
IO与NIO区别:其本质就是阻塞和非阻塞的区别。
阻塞概念:应用程序在获取网络数据的时候,如果网络传输数据很慢,就会一直等待,直到传输完毕为止。
非阻塞概念:应用程序直接可以获取已经准备就绪好的数据,无需等待。
IO为同步阻塞形式,NIO为同步非阻塞形式,NIO并没有实现异步,在JDK1.7升级NIO库包,支持异步非阻塞。
BIO:同步阻塞式IO,服务器实现模式为一个连接一个线程,即客户端有连接请求时服务器端就需要启动一个线程进行处理,如果这个链接不做任何事情会造成不必要的线程开销,当然可以通过线程池机制改善。
NIO:同步非阻塞式IO,服务器实现模式为一个请求一个线程,即客户端发送的链接请求都会注册到选择器上,选择器轮询到连接有IO请求时才启动一个线程进行处理。
AIO:异步非阻塞式IO,服务器实现模式为一个有效请求一个线程,客户端的IO请求都是由OS先完成在通知服务器应用去启动线程进行处理。
同步时,应用程序会直接参与IO读写操作,并且我们的应用程序会直接阻塞到某一个方法上,直到数据准备就绪,或者采用轮训的策略实时检查数据的就绪状态,如果就绪则获取数据。
异步时,则所有的IO读写操作交给操作系统,与我们的应用程序没有直接关系,我们程序不需要关系IO读写,当操作系统完成了IO读写操作时,会给我们应用程序发送通知,我们的应用程序直接拿走数据即可。
伪异步
由于BIO一个客户端需要一个线程去处理,因此我们进行优化,后端使用线程池来处理多个客户端的请求接入,形成客户端个数M,线程池最大的线程数N的比例关系,其中M可以远远大于N,通过线程池可以灵活的调配线程资源,设置线程的最大值,防止由于海量并发接入导致线程耗尽。
//服务器端
public class TCPServer {public static void main(String[] args) throws Exception {ExecutorService es = Executors.newCachedThreadPool();ServerSocket serverSocket = new ServerSocket(8989);try {while(true) {Socket accept = serverSocket.accept();es.execute(new Runnable() {public void run() {try {InputStream is = accept.getInputStream();byte[] bs = new byte[1024];int length = is.read(bs);System.out.println(new String(bs,0,length));} catch (Exception e) {}}});}} catch (Exception e) {}finally {serverSocket.close();}}
}//客户端
public class TCPClient {public static void main(String[] args) throws Exception {Socket s = new Socket("127.0.0.1", 8989);OutputStream os = s.getOutputStream();os.write("你好".getBytes());s.close();}
}
什么是阻塞
应用程序在获取网络数据的时候,如果网络传输很慢,那么程序就一直等着,直接到传输完毕。
什么是非阻塞
应用程序直接可以获取已经准备好的数据,无需等待。
IO为同步阻塞形式,NIO为同步非阻塞形式,NIO没有实现异步,在JDK1.7之后,升级NIO库包,支持异步非阻塞通讯模型。
//异步非阻塞
public class Client {public static void main(String[] args) throws Exception {//创建通道SocketChannel sc = SocketChannel.open(new InetSocketAddress("127.0.0.1", 8080));//切换异步非阻塞模式sc.configureBlocking(false);//设置缓冲去大小ByteBuffer bb = ByteBuffer.allocate(1024);//获取键盘输入的值Scanner s = new Scanner(System.in);while(s.hasNext()) {String str = s.next();//把获取的值写入缓冲区中bb.put(str.getBytes());bb.flip();//把缓冲区中的值写入通道中sc.write(bb);bb.clear();}sc.close();}
}public class Server {public static void main(String[] args) throws Exception {//创建通道ServerSocketChannel ssc = ServerSocketChannel.open();//切换到异步非阻塞模式ssc.configureBlocking(false);//绑定链接ssc.bind(new InetSocketAddress(8080));//获取选择器Selector open = Selector.open();//将通道注册到选择器,并指定监听接受事件ssc.register(open, SelectionKey.OP_ACCEPT);//轮训式获取选择已经准备就绪的事件while(open.select() > 0) {//获取当前选择器所有注册的监听事件Iterator<SelectionKey> it = open.selectedKeys().iterator();while(it.hasNext()) {//获取准备就绪的事件SelectionKey sk = it.next();//判断是什么事件准备就绪if(sk.isAcceptable()) {//接受就绪,获取客户端连接SocketChannel sc = ssc.accept();//设置非阻塞异步模式sc.configureBlocking(false);//将通道注册到服务器上sc.register(open, SelectionKey.OP_READ);} else if(sk.isReadable()) {//获取当前选择器就绪的通道SocketChannel s = (SocketChannel) sk.channel();ByteBuffer bb = ByteBuffer.allocate(1024);int len = 0;while((len = s.read(bb)) > 0) {bb.flip();System.out.println(new String(bb.array(),0,len));bb.clear();}}}it.remove();}}
}
选择KEY
SelectionKey.OP_CONNECT 可连接
SelectionKey.OP_ACCPT 可接受连接
SelectionKey.OP_READ 可读
SelectionKey.OP_WRITE 可写
如果要监听多种事件,可以用 | 操作符将常量连接起来。
更多推荐
NIO同步阻塞与同步非阻塞
发布评论