Java I/O的工作机制

前言:当前大量的数据在网络上极其活跃,随处流动,这个流动的过程中都会涉及到I/O问题,可以说大部分web应用的瓶颈都是在I/O上。

注:文章的“详情请看Pxx”指的是《深入分析 Java web技术内幕》的某一页

这篇文章主要讲解:Java I/O 类库的基本架构,磁盘I/O,网络I/O基本机制,以及一些I/O优化技巧。

1.Java I/O类库的基本架构

Java 1.4版本开始引入NIO,提升了I/O性能。

Java的I/O操作类都在包Java.io下,大概有将近80个类,这些类大概可以分作四种:

(1)基于字节操作的I/O接口:InputStream和OutputStream

(2)基于字符操作的I/O接口:Reader和Writer

-------------------传输数据的格式----------------------

(3)基于磁盘操作的I/O接口:File

(4)基于网络操作的I/O接口:Socket

------------------传输数据的方式-----------------------

注:虽然Socket类不在Java.io包下,但是I/O的核心问题就是 在 传输格式 和 传输方式 上,也就是把什么样的数据怎么写进去的问题。

2.针对以上四种I/O分类一一解析

    2.1字节操作I/O:

  2.2基于字符操作的I/O接口

无论是磁盘还是网络传输,最小的存储单位都是字节,而不是字符。所以io操作的是字节而不是字符。但是为什么还要字符操作的接口呢,那是因为我们的程序中通常操作的数据都是字符形式的,为了操作方便当然需要提供字符操作的接口了。字符到字节必须要经过编码转换。简单点说就是Writer和Reader来实现

 2.3字节和字符的转化接口

网络传输和数据持久化都是以字节形式存在的,所以要有对字符转化为字节的接口。

字节转换成字符:InputStreamReader;字符转换成字节:OutStreamWriter

 2.4磁盘I/O工作机制

在介绍Java读取和写入磁盘文件之前先看看应用程序访问文件有哪几种方式。

-----------------这里省略了吧,晦涩了点,详情请看《深入分析Java web技术内幕》P30~P33~---------------------------------------

3.Java序列化技术

序列化就是将对象转化成一串二进制表示的字节数组,通过保存或转移这些字节数据达到持久化的目的。实现方法是实现Java.io.Serializable.

----------------这里省略了吧,枯燥了点,详情请看《深入分析Java web技术内幕》P34-35~~------------------------------------------

注:在纯Java环境,Java序列化能够正常工作,但是在多语言环境下,用Java序列化存储之后,很难用其他语言来还原出结果。所以在这种多语言环境下要用通用的数据结构,比如JSON或者XML;也有比较好的序列化工具,比如Google的protobuf。

4.网络I/O工作机制:通信协议以及如何完成数据传输

------------待续---------

---16::43---

  4.1TCP状态转化:

---------------枯燥了点,详情请看P38~---------------------

注:搞清楚TCP连接的几种状态对我们调试网络程序非常有帮助,例如当我们压测一个网络程序的时候发现带宽,CPU,网卡都不是瓶颈的,但是性能就是跟不上,这是如果你看一下网络连接的状态,可能会发现由于网络连接的并发数不够导致连接处于都处于TIME_WAIT状态,这时候就要做TCP网络参数调优操作了~

 

  4.2影响网络传输的因素

》网络带宽:带宽就是一秒钟一条物理链路层最大能够传输的比特数,即b/s。

》传输距离:光纤,有速度,距离,就会有时间消耗

》TCP拥塞控制

  4.3Java Socket的工作机制

Socket这个概念没有一个具体的实体,它描述计算机之间完成相互通信的一种抽象功能。

Socket通信:主机A的应用程序想要跟主机B的应用程序通信,就必须建立Socket连接。建立Socket连接需要由底层TCP/IP协议来建立TCP连接,建立TCP连接需要底层IP协议来寻找网络中的目标主机。但是一台主机上面运行着多个应用程序,如何才能跟制定的应用程序进行通信就要 ,通过TCP 或者UDP 的地址也就是端口号来制定了。

  4.4 建立通信链路:这个在我的另一篇文章《http的一些基础》有提到过,client端建立socket实例,server端建立serversocket实例。

  4.5数据传输(Socket传输):

当连接建立成功,服务器和客户端都会有一个socket实例,每一个socket实例都有一个InputStream和OutputStream(字节流形式传输),并且通过这两个对象进行数据交换。当建立Socket对象的时候操作系统将会为InputStream和OutputStream分配一定大小的缓冲区。数据的写入和读取都是在这个缓冲区完成的。写入端将数据写到OutputStream的SendQ队列中,当队列填满时候,数据将会被转移到另一端的InputStream的RecvQ队列。如果这是RecvQ队列填满了,OutputStream的write方法就会阻塞知道RecvQ队列有足够空间容纳SendQ的数据。

  4.6NIO的工作方式

BIO也就是阻塞I/O,不管是磁盘I/O还是网络I/O,写入InputStream或者从OutputStream读取时都会产生阻塞的情况,一旦有阻塞,线程就会失去对CPU的使用权。这在大规模访问量和高性能的要求下是不能够被接受的。所以NIO闪亮登场!!

4.7NIO的工作机制

NIO更详细的介绍相关教程看这里

NIO核心概念:Channel类和Selector类

利用城市交通工具来比喻NIO的工作方式,Channel好比是一种交通工具比如汽车,而Selector可以比作是车站的车辆调度系统,它负责监控车站的每一辆车的当前运行状态,也就是他可以轮询每一个Channel的状态。这里还有一个Buffer类,Socket非常不透明,不可控制,相对而言,NIO引入了Channel,Selector,Buffer就是想把这些信息具体化。在Buffer中我们可以控制它的容量,是否扩容以及如何扩容。

典型的NIO代码,--------不好贴-------------详情请看P41~------------------

注:实际应用中:Server的监听是这样的,一个线程专门负责监听客户端的连接请求而且是以阻塞的方式执行的;而另外一个线程专门负责处理请求,这个专门处理请求的线程才会真正采用NIO方式,像Web服务器Tomcat和Jetty都使用这个处理方法。

 

《深入分析Java web技术内幕》mark:P40~

-----------continue---------------

5.I/O调优

磁盘I/O,网络I/O的常见优化方法:

  5.1磁盘I/O:我们的应用程序通常都需要从磁盘里面读取数据,而磁盘I/O是非常耗时间的。

性能检测:查看I/O wait指标,IOPS,现在为了提高磁盘的I/O 性能,通常采用一种叫做RAID的技术,就是将不同的磁盘组合起来的方式

            5.1.1提升IO性能:

》增加缓存,减少磁盘访问次数

》优化磁盘的管理系统,设计最优的磁盘方式策略(这是从操作系统层面考虑的)

》设计合理的磁盘数据存储块,以及访问这些数据块的策略,这是从应用层面考虑。例如,我们可以给存放的数据设计索引,通过寻址索引来加快和减少对磁盘的访问。还可以采用非阻塞,异步的方式加快磁盘访问速度。

》应用合理的RAID策略提升磁盘I/O

 

5.2TCP网络参数调优:增加可使用的主机端口数量、TCP连接复用,----------------------详情请看P51~-------------------------

 

5.3网络I/O优化:

》减少网络交互的次数:设置缓存,合并请求(同时查10个id,在访问一个页面有多个js,我们可以将多个js文件合并一个http链接中,每个文件用逗号隔开,然后发送到web后端服务器,根据这个URL拆分出各个文件,最后再一并打包发回到前端浏览器)

》减少网络传输数据量的大小:将数据压缩后再传输,设计简单的协议,尽量通过读取协议头来获取有用的价值信息。

》尽量减少编码:通常在网络传输数据都是以字节的形式,也就是说通常需要序列化,但是我们发送的数据通常都是字符形式的,字符到字节要编码,耗费时间,所以在数据进行网络传输之前先进行字符到字节转化的操作。

》同步异步:在一个任务序列中,I/O通常都是性能瓶颈,但是同步和异步的处理方式对程序的可靠性影响非常大,同步能够保证程序的可靠性,而异步可以提升程序的性能,必须在可靠性和性能之间做出抉择,没有完美的解决方法??

》阻塞和非阻塞:这里说的主要是从CPU的消耗上,阻塞就是CPU停下来等待一个慢的操作完成任务;非阻塞就是一个线程执行过程中有一个耗时的I/O操作,这个时候CPU转去执行另一个线程,等耗时的I/O操作完成之后再去完成这个线程的后续操作。表面上非阻塞的方式可以明显提高CPU的效率,但是也有一个后果就是系统的线程切换会增加。

》上面两种方式组合:同步阻塞,同步非阻塞,异步阻塞,异步非阻塞

         

注:虽然异步和非阻塞能提升I/O性能,但是也会带来一些额外的性能成本,例如会增加线程数量从而增加CPU 的消耗,同时程序设计复杂度也会提升。如果设计不合理,反倒会让性能下降,所以要根据应用场景来综合评估。

------------------P56-P59 讲了“适配器以及装饰器”--------------------------------------------------------

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值