Java NIO之理解I/O模型(一)

前言

本身之前在Java NIO这块儿,一直都是比较薄弱的,之前还由于这点知识而错失了一个机会。因此最近打算好好学习一下这部份内容,我想应该也会有朋友像我同样,一直想闹明白这块儿内容。可是一直无从下手,每次被问到什么NIO,BIO,AIO就慌,下面咱们先从一些基本概念来慢慢了解NIO这部份内容。数据库

同步与异步

同步和异步是比较好理解的,网上也有好多解释。下面我经过我的的理解来解释这两个概念可能会通俗一些,但愿能更好理解。bash

同步就是多个任务或事件在执行时须要按顺序逐个执行,若是排在顺序前面的任务或事件在执行的时候,排在后面的任务或事件就须要等待前面的执行完后才能够执行,这些任务或事件是不能并行执行的。同步执行任务能够被设计为可靠的任务序列,先后两个任务能够保持一致才算整个任务结束。网络

异步是多个任务或事件能够同时并行执行,前面的任务不会致使后面的任务的等待。由于是多个任务同时进行的,因此每一个任务之间不产生相互的依赖,因此没法保证可靠性。多线程

同步流程图异步

异步流程图分布式

同步示例代码ide

按顺序逐个执行的方法,test3会等待test1和test2都执行完后再执行。性能

异步示例代码学习

public static void testA(){
        new Thread(){
            @Override
            public void run() {
                System.out.println(">>>>>>>>>testA<<<<<<<<<<");
            }
        }.start();
}
public static void testB(){
        new Thread(){
            @Override
            public void run() {
                System.out.println(">>>>>>>>>testB<<<<<<<<<<");
            }
        }.start();
}
public static void testC(){
        new Thread(){
            @Override
            public void run() {
                System.out.println(">>>>>>>>>testC<<<<<<<<<<");
            }
        }.start();
}
public static void main(String[] args) {
        testA();
        testB();
        testC();
}复制代码

上面这段异步代码能够看出,testA、testB、testC三个方法各自有本身的线程来执行任务,五项不依赖因此不会形成有任务等待的状况。典型的异步处理机制。ui

虽然上面的异步用了三个线程来实现了,可是并不表明多线程就是异步,这是两个概念,多线程只是实现异步的一种方式。而异步是一种处理模式,除了多线程还能够有其余的方式来实现。

在生活中的例子咱们在打电话的时候就至关于同步,只有对方接通了才算任务执行成功。而发短信则是异步,短信发送后并不依赖接收者是否接收成功。

阻塞与非阻塞

阻塞是指当有任务在执行时,会发出一个请求操做,若是该请求操做须要的条件不知足的话,那么就会一直等待,直到条件知足后,才继续执行后面的其余工做

非阻塞是指当有任务在执行时,会发出一个请求操做,若是该请求操做须要的条件不知足的话,会当即返回一个标志信息告知条件不知足,而不会一直在等待下去

阻塞流程

非阻塞流程

有的人老是把同步、异步,与阻塞、非阻塞, 这两组概念给理解混了,可是其实这是两组彻底不一样的概念。

同步与异步这组概念的重点在于,前面的任务是否会致使整个流程的等待。

阻塞与非阻塞这组概念的重点在于,若是操做请求不知足条件是否会返回一个标志信息告知不知足条件。

其实理解阻塞与非阻塞能够从咱们一般所接触的线程阻塞来理解,当出现慢任务的时候,线程会发生阻塞,cpu会等待慢任务执行完成后再执行后续的任务。而非阻塞线程在执行这个慢任务的时候,会去作其余事情,当慢任务执行完成后,再去执行后面的任务。非阻塞虽然看似能够明显提升效率,可是系统的线程切换也是会形成时间损耗,因此须要合理利用。

同步IO与异步IO

同步IO是指,当一个线程在执行IO操做时,该线程在IO操做完成前,是会被阻塞的。

异步IO是指,当一个线程在执行IO操做时,该线程并不会被阻塞。

IO操做实际上是有一个过程的,咱们拿网络IO为例,一个网络IO主要会涉及到两个对象,一个是调用这个IO得线程,另外一个是系统内核。当一个read操做发生时,会经历两个阶段。

一、等待数据准备就绪。

二、将数据从内核拷贝到调用调用这个IO得线程中。

IO模型的区别主要都在这两个阶段上面因此很重要,咱们所说的同步与异步的区别,在于第二个阶段中,将数据从内核拷贝到线程(或进程)中,若是被阻塞了就同步,没有被阻塞就是异步。被阻塞了说明该阶段的操做是依赖用户线程的,而没有被阻塞说明不依赖用户线程,而依赖内核,因此异步是须要操做系统内核支持的。

阻塞IO与非阻塞IO

上面咱们在介绍同步IO与非同步IO的时候说到,同步与不一样步的区别在IO操做的第二个阶段,这节咱们说的阻塞IO与非阻塞IO则是发生在IO操做第一个阶段的。

阻塞IO是指当一个线程发起IO操做请求时,系统内核会去查看要操做的数据是否就绪,当是阻塞IO时,发现要操做是数据没有就绪,就会一直等待下去,直到数据准备就绪;当是非阻塞IO时若是数据没有准备好,就会返回一个标识信息告诉调用线程,当前操做数据没有准备就绪。当数据准备就绪后才会执行第一阶段。

其实阻塞IO与非阻塞IO的关键区别在于,是等待执行,仍是说当即返回一个通知标识。当数据没有准备好时就等待执行,而当当即返回一个通知标识时,线程会根据标识知道如今数据是个什么状况,若是没有准备好,那么线程会再次发起请求,知道数据准备好后当即执行。

两种方式的组合

虽然异步和非阻塞可以提高I/O的性能,可是也会带来一些额外的性能成本,例如:会增长线程数量,从而增长CPU的消耗,同时也会致使程序设计复杂度的上升。若是设计的不合理反而会致使性能降低,在实际设计时要分解应用场景总和评估。

下面这个表格就列出了同步异步与阻塞非阻塞组合起来的性能分析。

组合方式 性能分析
同步阻塞 最经常使用的一种用法,使用也是最简单的,可是I/O性能通常不好,CPU大部分处于空闲状态。
同步非阻塞

  提高I/O性能的经常使用手段,就是将I/O的阻塞改成非阻塞方式,尤为在网络I/O是长链接同事传输

数据也不不少的状况下,提高性能很是有效。

  这种方式一般能提高I/O性能,可是会增长CPU消耗,要考虑增长的I/O性能能不能补偿CPU的

消耗,也就是系统的瓶颈是在I/O上仍是在CPU上。

异步阻塞

  这种方式在分布式数据库中常常用到,例如,在一个分布式数据库中写一条记录,一般会有一份是

同步阻塞的记录,还有2~3份记录会写到其余机器上,这些备份记录一般都采用异步阻塞的方式写I/O。

  异步阻塞对网络I/O可以提高效率,尤为像上面这种同时写多份相同数据的状况。

异步非阻塞

  这种组合方式用起来比较复杂,只有在一些很是复杂的分布式状况下用,集群之间的消息同步机制

通常用这种I/O组合方式。

  它适合同时要传多份相同的数据到集群中不一样的机器,同时数据的传输量虽然不大却很是频繁的状况。

这种网络I/O用此方式性能达到最高。

文章会同步到个人公众号上面,欢迎关注。

相关文章
相关标签/搜索