java原理4:java的io网络模型
Posted 猿来如此dj
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java原理4:java的io网络模型相关的知识,希望对你有一定的参考价值。
文章目录
Java 网络IO模型简介
1:基础概念
正式开始之前,需要铺垫一些基本概念,以免接下来看到一脸懵逼。
我们都知道,在操作系统中,CPU负责执行指令,这些指令有些来自应用程序,有些是底层系统的自调用。有些指令是非常危险的,如清除内存,网络连接等等,如果错误调用的话有可能导致系统崩溃。因而CPU将指令分为特权指令和非特权指令,对于某些特定的指令,只需要操作系统及其相关模块进行调用。因而,根据这个特点,操作系统内部也划分出了内核态和用户态。
内核态拥有完全的底层资源控制权限,可以执行任何的CPU指令,访问任何内存地址,其占有的处理机是不允许被抢占的。
用户程序是运行在操作系统之上,这些程序运行时称之为用户态,用户态下不能直接访问底层硬件和内存地址,只能通过委托系统调用的方式来访问底层硬件和内存。
io操作就是一次读写,而读写数据分为两个步骤等待数据和将数据从内核拷贝到用户空间。
1:同步和异步
同步/异步关注的是消息通信机制。
同步:所谓同步,就是在发出一个功能调用时,在没有得到结果之前,该调用就不返回。等前一件做完了才能做下一件事。
异步:异步的概念和同步相对。当一个异步过程调用发出后,调用者若不能立刻得到结果,此时可以直接返回然后执行其他任务,等到获得了结果之后通过状态、通知或者回调等手段通知调用者。
同步、异步一般发生在不同的线程/进程之间,如Thread1和Thread2是同步执行还是异步执行的
2:阻塞和非阻塞
阻塞和非阻塞关注的是程序在等待调用结果时的状态。
阻塞: 阻塞调用是指调用返回之前,当前线程会被挂起,只有当调用得到结果后才返回。
非阻塞:与阻塞相反,非阻塞调用是指在不能立即得到结果之前,该函数不会将当前线程阻塞,而是立即返回。
当应用程序调用一个 IO 函数,其底层会委托操作系统的recvfrom()去完成,当数据还没有准备好时,revfrom会一直阻塞,等待数据准备好。当数据准备好后,从内核拷贝到用户空间,recvfrom 返回成功,IO函数调用完成。过程如下所示:
image-20200820165546288
2.1:阻塞IO
阻塞IO模型的优点是编程简单,但缺点是需要配合大量线程使用。应用进程没接收一个连接,就需要为此连接创建一个线程来处理该连接上的读写任务。
阻塞IO,指的是需要内核IO操作彻底完成后,才返回到用户空间执行用户的操作。阻塞指的是用户空间程序的执行状态。调用进程在等待数据的过程中不会被阻塞,而是会不断地轮询查看数据有没有准备好。当数据准备好后,将数据从内核空间拷贝到用户空间,完成IO函数的调用。等待数据的过程是非阻塞的,但数据拷贝时仍是阻塞的。过程如下所示:
2.2:非阻塞io
非阻塞io的优点在于可以实现使用一个线程同时处理多个连接的需求,减少线程的大量使用。缺点在于要不断地去轮询检查数据是否准备好,比较耗费CPU。
2.3:io复用
为了解决非阻塞IO不断轮询导致CPU占用升高的问题,出现了IO复用模型。IO复用中,使用其他线程帮助去检查多个线程数据的完成情况,提高效率。
Linux中提供了select、poll和epoll三种方式来实现IO复用。一个线程可以对多个IO端口进行监听,当有读写事件产生时会分发到具体的线程进行处理。过程如下所示:
IO复用只需要阻塞在select,poll或者epoll,可以同时处理和管理多个连接。缺点是当select、poll或者epoll 管理的连接数过少时,这种模型将退化成阻塞IO 模型。并且还多了一次系统调用:一次select、poll或者epoll 一次recvfrom。
3:同步/异步和阻塞/非阻塞
- 阻塞: 阻塞调用是指调用返回之前,当前线程会被挂起,只有当调用得到结果后才返回。
- 非阻塞:与阻塞相反,非阻塞调用是指在不能立即得到结果之前,该函数不会将当前线程阻塞,而是立即返回。
- 同步:所谓同步,就是在发出一个功能调用时,在没有得到结果之前,该调用就不返回。等前一件做完了才能做下一件事,有事件的执行先后顺序,同时只能干一件事。
- 异步:异步的概念和同步相对。当一个异步过程调用发出后,调用者不能立刻得到结果。实际处理这个调用的部件在完成后,通过状态、通知和回调来通知调用者。
两者的区别
- 同步和异步是针对执行结果的。请求者主动的,等待结果或者通过回调等状态获取执行结果
- 阻塞和非阻塞是是指等待结果时的状态。
阻塞/非阻塞更多的用来形容某次调用的属性(比如 read(),write() 是否是阻塞/非阻塞 ),多在系统内核和用户空间内发生,所以应用范围比较窄;
而同步/异步则更上层,通常指应用中各个功能/线程之间的关系(比如 Thread1 和 Thread2 是同步执行还是异步执行)。
3.1:同步非阻塞NIO
在内核数据没有准备好的阶段,用户线程发起IO请求时,立即返回(同步)。所以,为了读取到最终的数据,用户线程需要不断地发起IO系统调用(非阻塞)。
内核数据到达后,用户线程发起系统调用,用户线程阻塞。内核开始复制数据,它会将数据从内核缓冲区复制到用户缓冲区(用户空间的内存),然后内核返回结果(例如返回复制到的用户缓冲区的字节数)。
用户线程读到数据后,才会解除阻塞状态,重新运行起来。也就是说,用户进程需要经过多次的尝试,才能保证最终真正读到数据,而后继续执行。
4: redis为什么速度快
1:io复用
Redis网络模型是采用I/O多路复用器,对key的处理是单线程 避免了多线程之间的竞争,省去了线程切换带来的时间和空间上的性能开销,而且也不会导致死锁的问题。
2:基于内存的数据K-V操作,速度快,底层用了各种数据结构来保证对key的操作是快的
以上是关于java原理4:java的io网络模型的主要内容,如果未能解决你的问题,请参考以下文章
深入浅出Java并发编程指南「原理分析篇」360度全方位的教你认识网络IO模型
Java 四种常见网络IO模型以及selectpollepoll函数的简单介绍