前言

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

同步与异步

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

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

异步是多个任务或事件可以同时并行执行,前面的任务不会导致后面的任务的等待。因为是多个任务同时进行的,所以每个任务之间不产生相互的依赖,所以无法保证可靠性。

同步流程图

异步流程图

同步示例代码

public static void test1(){
System.out.println(">>>>>>>>>test1<<<<<<<<<<");
}
public static void test2(){
System.out.println(">>>>>>>>>test2<<<<<<<<<<");
}
public static void test3(){
System.out.println(">>>>>>>>>test3<<<<<<<<<<");
}
public static void main(String[] args) {
test1();
test2();
test3();
}

按顺序逐个执行的方法,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三个方法各自有自己的线程来执行任务,互相不依赖所以不会造成有任务等待的情况。典型的异步处理机制。

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

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

阻塞与非阻塞

阻塞是指当有任务在执行时,会发出一个请求操作,如果该请求操作需要的条件不满足的话,那么就会一直等待,直到条件满足后,才继续执行后面的其他工作

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

阻塞流程

非阻塞流程

有的人总是把同步、异步,与阻塞、非阻塞, 这两组概念给理解混了,但是其实这是两组完全不同的概念。

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

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

其实理解阻塞与非阻塞可以从我们通常所接触的线程阻塞来理解,当出现慢任务的时候,线程会发生阻塞,cpu会等待慢任务执行完成后再执行后续的任务。而非阻塞线程在执行这个慢任务的时候,会去做其他事情,当慢任务执行完成后,再去执行后面的任务。非阻塞虽然看似可以明显提高效率,但是系统的线程切换也是会造成时间损耗,所以需要合理利用。

同步IO与异步IO

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

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

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

1、等待数据准备就绪。

2、将数据从内核拷贝到调用这个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用此方式性能达到最高。

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

最新文章

  1. node-mysql 在4.2.0的时候遇到的错误
  2. _stdcall,_cdecl区别
  3. asp.net MVC中使用entity framework出现从 datetime2 数据类型到 datetime 数据类型的转换产生一个超出范围的值”的处理
  4. python基础学习二——第二天
  5. vsftpd 搭建与介绍
  6. Stanford机器学习---第八讲. 支持向量机SVM
  7. Codeforces Round #332 (Div. 2) A. Patrick and Shopping 水题
  8. LINQ动态查询类--[DynamicLinqExpressions]
  9. QT TCP/IP
  10. 【源码】otter工程结构
  11. 2x or 3X的图
  12. Linux下mysql定时自动备份并FTP到远程脚本
  13. SQL分别求行、列的平均值
  14. Elastic Job入门(1) - 简介
  15. 第 8 章 容器网络 - 059 - 安装配置 flannel
  16. C++手机通讯录排序
  17. PHPCMS源码分析
  18. jfinal视频目录
  19. EMQ学习 ---集群
  20. ACM-百度之星资格赛之Energy Conversion——hdu4823

热门文章

  1. Python基础总结之第一天(新手可相互督促)
  2. linux基础命令期末考试总结
  3. MyBatis 文档 完整版
  4. vue教程二 vue组件(3)
  5. 【MySQL】
  6. 【Android】Theme.AppCompat.Light 问题
  7. 利用dockerfile 安装一个tomcat7
  8. ASP.NET Core MVC 之局部视图(Partial Views)
  9. strus 上传文件
  10. go杂货铺