NIO同步阻塞与同步非阻塞

编程入门 行业动态 更新时间:2024-10-19 12:37:26

<a href=https://www.elefans.com/category/jswz/34/1733878.html style=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同步阻塞与同步非阻塞

本文发布于:2024-03-09 10:08:20,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1724685.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:NIO

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!