When studying both the Java NIO and IO API's, a question quickly pops into mind:
When should I use IO and when should I use NIO?
In this text I will try to shed some light on the differences between Java NIO and IO, their use cases, and how they affect the design of your code.
Main Differences of Java NIO and IO
The table below summarizes the main differences between Java NIO and IO. I will get into more detail about each difference in the sections following the table.
IO | NIO |
Stream oriented | Buffer oriented |
Blocking IO | Non blocking IO |
Selectors |
Stream Oriented vs. Buffer Oriented
The first big difference between Java NIO and IO is that IO is stream oriented, where NIO is buffer oriented. So, what does that mean?
Java IO being stream oriented means that you read one or more bytes at a time, from a stream. What you do with the read bytes is up to you. They are not cached anywhere. Furthermore, you cannot move forth and back in the data in a stream. If you need to move forth and back in the data read from a stream, you will need to cache it in a buffer first.
Java NIO's buffer oriented approach is slightly different. Data is read into a buffer from which it is later processed. You can move forth and back in the buffer as you need to. This gives you a bit more flexibility during processing. However, you also need to check if the buffer contains all the data you need in order to fully process it. And, you need to make sure that when reading more data into the buffer, you do not overwrite data in the buffer you have not yet processed.
Blocking vs. Non-blocking IO
Java IO's various streams are blocking. That means, that when a
thread invokes a read()
or write()
, that thread is blocked until there is some
data to read, or the data is fully written.
The thread can do nothing else in the meantime.
Java NIO's non-blocking mode enables a thread to request reading data from a channel, and only get what is currently available, or nothing at all, if no data is currently available. Rather than remain blocked until data becomes available for reading, the thread can go on with something else.
The same is true for non-blocking writing. A thread can request that some data be written to a channel, but not wait for it to be fully written. The thread can then go on and do something else in the mean time.
What threads spend their idle time on when not blocked in IO calls, is usually performing IO on other channels in the meantime. That is, a single thread can now manage multiple channels of input and output.
Selectors
Java NIO's selectors allow a single thread to monitor multiple channels of input. You can register multiple channels with a selector, then use a single thread to "select" the channels that have input available for processing, or select the channels that are ready for writing. This selector mechanism makes it easy for a single thread to manage multiple channels.
How NIO and IO Influences Application Design
Whether you choose NIO or IO as your IO toolkit may impact the following aspects of your application design:
- The API calls to the NIO or IO classes.
- The processing of data.
- The number of thread used to process the data.
The API Calls
Of course the API calls when using NIO look different than when
using IO. This is no surprise.
Rather than just read the data byte for byte from e.g. an InputStream
,
the data
must first be read into a buffer, and then be processed from there.
The Processing of Data
The processing of the data is also affected when using a pure NIO design, vs. an IO design.
In an IO design you read the data byte for byte from an InputStream
or
a Reader
. Imagine you were processing a stream of line
based textual data.
For instance:
Name: Anna Age: 25 Email: anna@mailserver.com Phone: 1234567890
This stream of text lines could be processed like this:
InputStream input = ... ; // get the InputStream from the client socket BufferedReader reader = new BufferedReader(new InputStreamReader(input)); String nameLine = reader.readLine(); String ageLine = reader.readLine(); String emailLine = reader.readLine(); String phoneLine = reader.readLine();
Notice how the processing state is determined by how far the program
has executed. In other words,
once the first reader.readLine()
method returns, you
know for sure that a full line
of text has been read. The readLine()
blocks until a
full line is read, that's why.
You also know that this line contains the name. Similarly, when the
second readLine()
call returns, you know that this line contains the age etc.
As you can see, the program progresses only when there is new data to read, and for each step you know what that data is. Once the executing thread have progressed past reading a certain piece of data in the code, the thread is not going backwards in the data (mostly not). This principle is also illustrated in this diagram:
Java IO: Reading data from a blocking stream. |
A NIO implementation would look different. Here is a simplified example:
ByteBuffer buffer = ByteBuffer.allocate(48); int bytesRead = inChannel.read(buffer);
Notice the second line which reads bytes from the channel into the ByteBuffer
.
When that method call returns you don't know if all the data you
need is inside the buffer.
All you know is that the buffer contains some bytes. This makes
processing somewhat harder.
Imagine if, after the first read(buffer)
call, that all
what was read into the
buffer was half a line. For instance, "Name: An". Can you process
that data? Not really.
You need to wait until at leas a full line of data has been into the
buffer, before it
makes sense to process any of the data at all.
So how do you know if the buffer contains enough data for it to make sense to be processed? Well, you don't. The only way to find out, is to look at the data in the buffer. The result is, that you may have to inspect the data in the buffer several times before you know if all the data is inthere. This is both inefficient, and can become messy in terms of program design. For instance:
ByteBuffer buffer = ByteBuffer.allocate(48); int bytesRead = inChannel.read(buffer); while(! bufferFull(bytesRead) ) { bytesRead = inChannel.read(buffer); }
The bufferFull()
method has to keep track of how much
data is read into the buffer,
and return either true
or false
, depending
on whether the buffer is
full. In other words, if the buffer is ready for processing, it is
considered full.
The bufferFull()
method scans through the buffer, but
must leave the buffer in
the same state as before the bufferFull()
method was
called. If not, the next
data read into the buffer might not be read in at the correct
location. This is not impossible,
but it is yet another issue to watch out for.
If the buffer is full, it can be processed. If it is not full, you might be able to partially process whatever data is there, if that makes sense in your particular case. In many cases it doesn't.
The is-data-in-buffer-ready loop is illustrated in this diagram:
Java NIO: Reading data from a channel until all needed data is in buffer. |
Summary
NIO allows you to manage multiple channels (network connections or files) using only a single (or few) threads, but the cost is that parsing the data might be somewhat more complicated than when reading data from a blocking stream.
If you need to manage thousands of open connections simultanously, which each only send a little data, for instance a chat server, implementing the server in NIO is probably an advantage. Similarly, if you need to keep a lot of open connections to other computers, e.g. in a P2P network, using a single thread to manage all of your outbound connections might be an advantage. This one thread, multiple connections design is illustrated in this diagram:
Java NIO: A single thread managing multiple connections. |
If you have fewer connections with very high bandwidth, sending a lot of data at a time, perhaps a classic IO server implementation might be the best fit. This diagram illustrates a classic IO server design:
Java IO: A classic IO server design - one connection handled by one thread. |
相关推荐
Peakdet 是一个 NodeJS 库,用于检测数据中的峰谷。 Peakdet 采用的来检测峰值并将其打包为库并添加测试。...// Call the peakdet function, the second argument is the minimum differece // between the
To discover the spectra of them present obvious difference and the spectra for the blood of the different kind of the patient also present obvious differece, but the spectra of the specifieness ...
#CodeQuiz CodeQuiz 是一款使用 Kivy 框架制作的游戏。 他是一个测验由四个选项组成,Ruby、Python、Javascript 和 C#。... 提交它git commit -m 'the differece' 推送它git push origin name-your-feature 创建
项目中常见的问题,记录一下解决方案
2024-2025第一学期一上U1~3.pdf
redis是一个key-value存储系统。和Memcached类似,它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、zset(sortedset --有序集合)和hash(哈希类型)。这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。在此基础上,redis支持各种不同方式的排序。与memcached一样,为了保证效率,数据都是缓存在内存中。区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步。感兴趣的朋友可以过来看看
【项目资源】:包含前端、后端、移动开发、操作系统、人工智能、物联网、信息化管理、数据库、硬件开发、大数据、课程资源、音视频、网站开发等各种技术项目的源码。包括STM32、ESP8266、PHP、QT、Linux、iOS、C++、Java、python、web、C#、EDA、proteus、RTOS等项目的源码。【项目质量】:所有源码都经过严格测试,可以直接运行。功能在确认正常工作后才上传。【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。【附加价值】:项目具有较高的学习借鉴价值,也可直接拿来修改复刻。对于有一定基础或热衷于研究的人来说,可以在这些基础代码上进行修改和扩展,实现其他功能。【沟通交流】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。鼓励下载和使用,并欢迎大家互相学习,共同进步。
全国月尺度平均气温数据集(1961-2022, 0.25° × 0.25°)是一个高分辨率的网格化平均气温数据集,覆盖了中国大陆及周边地区。 该数据集通过科学方法整合气象观测和再分析数据,为气候研究、生态模型、农业生产、以及水资源管理等领域提供了重要支持。 数据下载后可显示详细信息。
yolo系列算法目标检测数据集,包含标签,可以直接训练模型和验证测试,数据集已经划分好,包含数据集配置文件data.yaml,适用yolov5,yolov8,yolov9,yolov7,yolov10,yolo11算法; 包含两种标签格:yolo格式(txt文件)和voc格式(xml文件),分别保存在两个文件夹中; yolo格式:<class> <x_center> <y_center> <width> <height>, 其中: <class> 是目标的类别索引(从0开始)。 <x_center> 和 <y_center> 是目标框中心点的x和y坐标,这些坐标是相对于图像宽度和高度的比例值,范围在0到1之间。 <width> 和 <height> 是目标框的宽度和高度,也是相对于图像宽度和高度的比例值
模拟退火算法shell脚本编程实践,分享给有需要的人,仅供参考。内容来源于网络分享,如有侵权请联系我删除。另外如果没有积分的同学需要下载,请私信我。
基于PCIe接口的高性能视频编辑系统
python爬虫入门,分享给有需要的人,仅供参考。内容来源于网络分享,如有侵权请联系我删除。另外如果没有积分的同学需要下载,请私信我。
在线音乐网站的设计与实现
电工与电子技术课程标准.doc
根据搜索结果,以下是一条关于社科数据的内容介绍:本数据集涵盖了2015至2021年间全国各地级市的关键经济指标,包括人口数量、城镇居民人均可支配收入、进出口总额以及社会消费品零售总额。这些数据为研究区域经济发展提供了宝贵的信息资源,来源于各省市统计年鉴及国家统计局的官方数据,确保了数据的权威性和准确性。数据内容全面,缺失值较少,适合用于宏观经济分析、政策评估以及学术研究等多个领域。通过这些数据,研究者可以深入了解中国各地区在不同年份的经济表现和发展趋势。
项目中常见的问题,记录一下解决方案
yolo系列算法目标检测数据集,包含标签,可以直接训练模型和验证测试,数据集已经划分好,包含数据集配置文件data.yaml,适用yolov5,yolov8,yolov9,yolov7,yolov10,yolo11算法; 包含两种标签格:yolo格式(txt文件)和voc格式(xml文件),分别保存在两个文件夹中; yolo格式:<class> <x_center> <y_center> <width> <height>, 其中: <class> 是目标的类别索引(从0开始)。 <x_center> 和 <y_center> 是目标框中心点的x和y坐标,这些坐标是相对于图像宽度和高度的比例值,范围在0到1之间。 <width> 和 <height> 是目标框的宽度和高度,也是相对于图像宽度和高度的比例值
6
【项目资源】:包含前端、后端、移动开发、操作系统、人工智能、物联网、信息化管理、数据库、硬件开发、大数据、课程资源、音视频、网站开发等各种技术项目的源码。包括STM32、ESP8266、PHP、QT、Linux、iOS、C++、Java、python、web、C#、EDA、proteus、RTOS等项目的源码。【项目质量】:所有源码都经过严格测试,可以直接运行。功能在确认正常工作后才上传。【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。【附加价值】:项目具有较高的学习借鉴价值,也可直接拿来修改复刻。对于有一定基础或热衷于研究的人来说,可以在这些基础代码上进行修改和扩展,实现其他功能。【沟通交流】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。鼓励下载和使用,并欢迎大家互相学习,共同进步。
S家LPDDR5/4/4X 控制器,针对功耗、延迟、带宽和面积进行了优化,支持 JEDEC 标准 LPDDR5、LPDDR4 和 LPDDR4X SDRAM。控制器通过 DFI 5.0 接口连接到 S家LPDDR5/4/4X PHY 或其他 LPDDR5/4/4X PHY,以创建一个完整的内存接口解决方案。S LPDDR5/4/4X 控制器包括软件配置寄存器,可通过 AMBA 3.0 APB 接口访问。 // Key Used : DWC-DDRCTL (IP access) // Key Used : DWC-LPDDR54-CONTROLLER (Add-on feature access: DWC LPDDR5/4/4X Controller) 注意:压缩包只有IP使用文档,完整IP及无加密SV代码压缩包有获取方式。