详解 同步异步阻塞非阻塞 与 BIO NIO AIO区别多路复用
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了详解 同步异步阻塞非阻塞 与 BIO NIO AIO区别多路复用相关的知识,希望对你有一定的参考价值。
(目录)
一、IO 介绍
IO
的全称其实是:Input/Output
的缩写
传统的 IO
大致可以分为 4种类型
:
那内核是如何进行IO交互的呢?
对应抽象到java的socket代码简单示例如下:
public class SocketServer
public static void main(String[] args) throws Exception
// 监听指定的端口
int port = 8080;
ServerSocket server = new ServerSocket(port);
// server将一直等待连接的到来
Socket socket = server.accept();
// 建立好连接后,从socket中获取输入流,并建立缓冲区进行读取
InputStream inputStream = socket.getInputStream();
byte[] bytes = new byte[1024];
int len;
while ((len = inputStream.read(bytes)) != -1)
//获取数据进行处理
String message = new String(bytes, 0, len,"UTF-8");
// 省略……
二、同步与异步
同步 和 异步 指的是:
假设我们的执行流程中:依次是方法一和方法二
同步与异步是从多个线程之间的协调来实现效率差异
三、阻塞与非阻塞
阻塞与非阻塞
主要是从 CPU 的消耗上来说
:
虽然表面上看 非阻塞的方式可以明显的提高 CPU 的利用率
,但是也带了另外一种后果就是系统的线程切换增加
。增加的 CPU 使用时间能不能补偿系统的切换成本需要好好评估。
阻塞与非阻塞关注的是线程是否在原地等待
四、BIO NIO AIO
1. BIO
2. NIO
NIO
也叫Non-Blocking IO 是同步非阻塞的IO模型
。
Java中的NIO 是new IO的意思
。其实是NIO加上IO多路复用技术
。普通的NIO是线程轮询查看一个IO缓冲区是否就绪,而Java中的new IO指的是线程轮询地去查看一堆IO缓冲区中哪些就绪,这是一种IO多路复用的思想
。IO多路复用模型中,将检查IO数据是否就绪的任务,交给系统级别的select或epoll模型,由系统进行监控,减轻用户线程负担。
3. AIO
AIO
是真正意义上的异步非阻塞IO模型
。
AIO可以做到真正的异步的操作,但实现起来比较复杂,支持纯异步IO的操作系统非常少,目前也就windows是IOCP技术实现了,而在Linux上,底层还是是使用的epoll实现的。
总结:
举个例子:
哪种方式更有效率呢?是不是一目了然呢?
五、Socket 和 NIO 的多路复用
1. 传统的 Socket 实现
代码如下:
int port = 4343; //端口号
// Socket 服务器端(简单的发送信息)
Thread sThread = new Thread(new Runnable()
@Override
public void run()
try
ServerSocket serverSocket = new ServerSocket(port);
while (true)
// 等待连接
Socket socket = serverSocket.accept();
Thread sHandlerThread = new Thread(new Runnable()
@Override
public void run()
try (PrintWriter printWriter = new PrintWriter(socket.getOutputStream()))
printWriter.println("hello world!");
printWriter.flush();
catch (IOException e)
e.printStackTrace();
);
sHandlerThread.start();
catch (IOException e)
e.printStackTrace();
);
sThread.start();
// Socket 客户端(接收信息并打印)
try (Socket cSocket = new Socket(InetAddress.getLocalHost(), port))
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(cSocket.getInputStream()));
bufferedReader.lines().forEach(s -> System.out.println("客户端:" + s));
catch (UnknownHostException e)
e.printStackTrace();
catch (IOException e)
e.printStackTrace();
- 调用 accept 方法,阻塞等待客户端连接;
- 利用 Socket 模拟了一个简单的客户端,只进行连接、读取和打印;
以上的流程,如下图:
2. NIO 多路复用
介于以上高并发的问题,NIO 的多路复用功能就显得意义非凡了
。
// NIO 多路复用
ThreadPoolExecutor threadPool = new ThreadPoolExecutor(4, 4,
60L, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
threadPool.execute(new Runnable()
@Override
public void run()
try (Selector selector = Selector.open();
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();)
serverSocketChannel.bind(new InetSocketAddress(InetAddress.getLocalHost(), port));
serverSocketChannel.configureBlocking(false);
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
while (true)
selector.select(); // 阻塞等待就绪的Channel
Set<SelectionKey> selectionKeys = selector.selectedKeys();
Iterator<SelectionKey> iterator = selectionKeys.iterator();
while (iterator.hasNext())
SelectionKey key = iterator.next();
try (SocketChannel channel = ((ServerSocketChannel) key.channel()).accept())
channel.write(Charset.defaultCharset().encode("你好,世界"));
iterator.remove();
catch (IOException e)
e.printStackTrace();
);
// Socket 客户端(接收信息并打印)
try (Socket cSocket = new Socket(InetAddress.getLocalHost(), port))
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(cSocket.getInputStream()));
bufferedReader.lines().forEach(s -> System.out.println("NIO 客户端:" + s));
catch (IOException e)
e.printStackTrace();
下面的图,可以有效的说明 NIO 复用的流程:
就这样 NIO 的多路复用就大大提升了服务器端响应高并发的能力。
以上是关于详解 同步异步阻塞非阻塞 与 BIO NIO AIO区别多路复用的主要内容,如果未能解决你的问题,请参考以下文章
(转)IO复用,AIO,BIO,NIO,同步,异步,阻塞和非阻塞 区别
IO复用,AIO,BIO,NIO,同步,异步,阻塞和非阻塞 区别