前言

自己以前在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用此方式性能达到最高。

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

Java NIO之理解I/O模型的更多相关文章

  1. Java NIO之理解I/O模型(二)

    前言 上一篇文章讲解了I/O模型的一些基本概念,包括同步与异步,阻塞与非阻塞,同步IO与异步IO,阻塞IO与非阻塞IO.这次一起来了解一下现有的几种IO模型,以及高效IO的两种设计模式,也都是属于IO ...

  2. Java NIO:浅析I/O模型

    也许很多朋友在学习NIO的时候都会感觉有点吃力,对里面的很多概念都感觉不是那么明朗.在进入Java NIO编程之前,我们今天先来讨论一些比较基础的知识:I/O模型.下面本文先从同步和异步的概念 说起, ...

  3. Java NIO:浅析I/O模型(转)

    原文链接:http://www.cnblogs.com/dolphin0520/p/3916526.html 以下是本文的目录大纲: 一.什么是同步?什么是异步? 二.什么是阻塞?什么是非阻塞? 三. ...

  4. Java NIO的理解和应用

    Java NIO是一种基于通道和缓冲区的I/O方式,已经被广泛的应用,成为解决高并发与大量连接和I/O处理问题的有效方式. Java NIO相关组件 Java NIO主要有三个核心部分组成,分别是:C ...

  5. JAVA NIO的理解

    在使用JAVA提供的Socket的IO方法时,服务端为了方便操作,会为每一个连接新建一个线程,一个线程处理一个客户端的数据交互.但是当大量客户端同服务端连接时,会创建大量的线程,线程之间的切换会严重影 ...

  6. Java NIO之Java中的IO分类

    前言 前面两篇文章(Java NIO之理解I/O模型(一).Java NIO之理解I/O模型(二))介绍了,IO的机制,以及几种IO模型的内容,还有涉及到的设计模式.这次要写一些更贴近实际一些的内容了 ...

  7. Java NIO理解与使用

    https://blog.csdn.net/qq_18860653/article/details/53406723 Netty的使用或许我们看着官网user guide还是很容易入门的.因为java ...

  8. Java多线程:Linux多路复用,Java NIO与Netty简述

    JVM的多路复用器实现原理 Linux 2.5以前:select/poll Linux 2.6以后: epoll Windows: IOCP Free BSD, OS X: kqueue 下面仅讲解L ...

  9. Netty精粹之JAVA NIO开发需要知道的

    学习Netty框架以及相关源码也有一小段时间了,恰逢今天除夕,写篇文章总结一下.Netty是个高效的JAVA NIO框架,总体框架基于异步非阻塞的设计,基于网络IO事件驱动,主要贡献在于可以让用户基于 ...

随机推荐

  1. JS中构造函数和普通函数有什么区别

    JS中构造函数有普通函数有什么区别? 1.一般规则 构造函数都应该以 一个大写字母开头,eg: function Person(){...} 而非构造函数则应该以一个小写字母开头,eg: functi ...

  2. 【iOS】arc4random() 产生随机数

    通过 arc4random() 获取 0 到 x-1 之间的整数的代码如下: int value = arc4random() % x; 获取 1 到 x 之间的整数的代码如下: ; PS: 这里用到 ...

  3. Nginx安装(详细版本)

    Nginx安装文档 前言: 最近,系统部署人员那边,让我们给写一个傻瓜式的Nginx安装过程.所以就有了这个文档,本着独乐乐不如众乐乐,就分享一下.我觉得对入门小白来说,有图,乃至运行过程图,是很重要 ...

  4. oracle的本地远程连接和配置

    Oracle数据库的远程连接可以通过多种方式来实现,本文我们主要介绍四种远程连接的方法和注意事项,并通过示例来说明,接下来我们就开始介绍. 第一种情况: 若oracle服务器装在本机上,那就不多说了, ...

  5. div 环形排列

    javascript-按圆形排列DIV元素(一)---- 分析 效果图: 一.分析图: 绿色边框内:外层的DIV元素,相对定位; 白色圆形框:辅助分析的想象形状; 白点:为白色圆形的圆心点,中心点,点 ...

  6. 【kafka】一、消息队列

    在高并发的应用场景中,由于来不及同步处理请求,接收到的请求往往会发生阻塞.例如,大量的插入.更新请求同时到达数据库,这会导致行或表被锁住,最后会因为请求堆积过多而触发“连接数过多的异常” 的错误.因此 ...

  7. C语言编程入门之--第五章C语言基本运算和表达式-part1

    导读:程序要完成高级功能,首先要能够做到基本的加减乘除.本章从程序中变量的概念开始,结合之前学的输出函数和新介绍的输入函数制作简单人机交互程序,然后讲解最基础的加减法运算,自制简单计算器程序练手. 5 ...

  8. Serilog 自定义Enricher 来增加记录的信息

    Serilog 自定义Enricher 来增加记录的信息 Intro Serilog 是 .net 里面非常不错的记录日志的库,结构化日志记录,而且配置起来很方便,自定义扩展也很方便 Serilog ...

  9. Go中的函数和闭包

    函数参数和返回值的写法 如果有多个参数是同一个类型,可以简略写: func testReturnFunc(v1,v2 int)(int,int) { x1 := 2 * v1 x2 := 3 * v2 ...

  10. 【CodeForces - 1200C】Round Corridor (数论gcd)

    Round Corridor  Descriptions Amugae位于一个非常大的圆形走廊中.走廊由两个区域组成.内部区域等于nñ扇区,外部区域等于m米部门.在相同区域(内部或外部)的每对扇区之间 ...