1、stream vs channel
通道(Channel):由 java.nio.channels 包定义 的。Channel 表示 IO 源与目标打开的连接。Channel 类似于传统的“流”。只不过 Channel 本身不能直接访问数据,Channel 只能与 Buffer 进行交互。(Channel本身不存储数据,因此需要配合缓冲区进行传输)
Channel 如何做到异步?
例如下图,我们应NIO的 Selector来监听 多个Channel,由于Channel是既可以读也可以写的,因此Selector监听Channel时,并不需要像BIO一样,阻塞到Channel有数据才返回,则是可以达到 当Channel有数据时,主动去通知Selector,让Selector去处理,这样的话,Selector就不需要阻塞了,这就是Channel的异步。
最明显的区别:一个是阻塞读取,一个是到达读取
stream 是BIO,也就是阻塞模式,分IN OUT两个,无论是IN还是OUT,在进行消息处理是是阻塞当前线程的,也就是需要等待对方的数据到达。
channel 是NIO,可以看作其包含了INOUT是一个通道的概念,channel的实现有很多,针对本地文件的,针对网络的,针对内存的,不同的其表现并不完全相同,但可以理解为:channel的数据消费是将数据写入缓冲区buffer,或从buffer读取数据;这个过程是可以通过selector来辅助监听channel的状态
stream不会自动缓冲数据,channel会利用系统提供的发送缓冲区,接收缓冲区(更为底层)
stream仅支持阻塞 API,channel同时支持阻塞,非阻塞API,网络channel可配合selector实现多路复用
二者均为全双工,即读写可以同时进行
2、IO模型
同步阻塞、非同步阻塞、多路复用 (都属于同步IO) : 异步阻塞(没有此情况)、异步非阻塞 (异步IO)
- 同步:线程自己去获取结果(一个线程)
- 异步:线程自己不去获取结果,而是由其他线程获取结果(至少两个线程)。
- 异步只有非阻塞
- 异步只有非阻塞
网络io模型
-
阻塞IO :用户线程在读取期间被阻塞掉了,在读取期间不能执行其他的东西。
-
非阻塞IO:用户线程一直循环去访问内核空间,是否有数据,如果没有不会阻塞,会直接返回用户空间;直到读取到数据;进行复制数据,复制数据期间也还是会阻塞,直到复制完成返回。
-
多路复用:不会直接去调用read方法,会先去调用select,阻塞住,直到发送read事件,才会去内核空间读取复制数据到用户线程回来
-
阻塞io情况:线程执行完read事件后来了一个accept事件,他会去建立连接,中间是 不能继续去接收第一个channel的read事件的,需要等channel2连接建立之后才会去执行read事件
-
多路复用情况:select方法执行只会,就会去等待事件的发生,当事件来的时候,就会立即触发select,把事件全部注册到select中;如果多个事件一起发生,则会一起把事件注册回来,然后再去把事件执行掉,不会再等待c2,完成才会去执行把c3注册事件。
-
-
信号驱动
-
异步IO:
-
异步读取文件
-
使用
AsynchronousFileChannel类实现
- 多线程情况下,当主线程执行完了的时候,即使守护线程仍然还在执行,也会结束
守护线程
指为其他线程服务的线程。在JVM中,所有非守护线程都执行完毕后,无论有没有守护线程,虚拟机都会自动退出。而如果有非守护线程未执行完时,则JVM不会关闭
public static void main(String[] args) throws IOException { try (AsynchronousFileChannel channel = AsynchronousFileChannel.open(Paths.get("words2.txt"), StandardOpenOption.READ)){ /*参数1 ByteBuffer * 参数2 读取的起始位置 * 参数3 附件 * 参数4 回调对象 CompletionHandler * */ ByteBuffer buffer = ByteBuffer.allocate(16); log.debug("read begin..."); channel.read(buffer, 0,buffer, new CompletionHandler<Integer ,ByteBuffer>() { @Override //read 成功 (实际字节数,传入的buffer) public void completed(Integer result, ByteBuffer attachment) { log.debug("read...{}",result); attachment.flip(); String a = StandardCharsets.UTF_8.decode(attachment).toString(); log.debug("read...{}",a); } @Override //read 失败 public void failed(Throwable exc, ByteBuffer attachment) { exc.printStackTrace(); } }); log.debug("read end..."); } catch (IOException e) { e.printStackTrace(); } System.in.read(); }
-
参考:uxil网络编程