Java性能调优实战------模块二:Java 编程性能调优

03 | 字符串性能优化不容小觑,百M内存轻松存储几十G数据

  • String对象是如何实现的?
  • String对象的不可变性
    在这里插入图片描述
  • String对象的优化
    • 1.如何构建超大字符串?
    • 2.如何使用 String.intern 节省内存?
    • 3.如何使用字符串的分割方法?

04 | 慎重使用正则表达式

05 | ArrayList还是LinkedList?使用不当性能差千倍

  • 初识List接口

  • ArrayList是如何实现的?

    • 问题1:我们在查看ArrayList的实现类源码时,你会发现对象数组elementData使用了transient修饰,我们知道transient关键字修饰该属性,则表示该属性不会被序列化,然而我们并没有看到文档中说明ArrayList不能被序列化,这是为什么?
    • 问题2:我们在使用ArrayList进行新增、删除时,经常被提醒“使用ArrayList做新增删除操作会影响效率”。那是不是ArrayList在大量新增元素的场景下效率就一定会变慢呢?
    • 问题3:如果让你使用for循环以及迭代循环遍历一个ArrayList,你会使用哪种方式呢?原因是什么?
    • 1.ArrayList实现类
    • 2.ArrayList属性
    • 3.ArrayList构造函数
    • 4.ArrayList新增元素
    • 5.ArrayList删除元素
    • 6.ArrayList遍历元素
  • LinkedList是如何实现的?

    • 1.LinkedList实现类
    • 2.LinkedList属性
    • 3.LinkedList新增元素
    • 4.LinkedList删除元素
    • 5.LinkedList遍历元素
  • 1.ArrayList和LinkedList新增元素操作测试

  • 2.ArrayList和LinkedList删除元素操作测试

  • 3.ArrayList和LinkedList遍历元素操作测试

06 | Stream如何提高遍历集合效率?

  • 什么是Stream?
  • Stream如何优化遍历?
    • 1.Stream操作分类
      在这里插入图片描述

    • 2.Stream源码实现

    • 3.Stream操作叠加

    • 4.Stream并行处理

    • 合理使用Stream

测试性能比较:在串行处理操作中,在并行处理操作中。

07 | 深入浅出HashMap的设计与优化

  • 常用的数据结构
    • 数组
    • 链表
    • 哈希表
  • HashMap的实现结构
  • HashMap的重要属性
  • HashMap添加元素优化
  • HashMap获取元素优化
  • HashMap扩容优化
    在这里插入图片描述

08 | 网络通信优化之I/O模型:如何解决高并发下I/O瓶颈?

  • 什么是I/O: I/O是机器获取和交换信息的主要渠道,而流是完成I/O操作的主要方式。
    • 1.字节流
    • 2.字符流

“不管是文件读写还是网络发送接收,信息的最小存储单元都是字节,那为什么I/O流操作要分为字节流操作和字符流操作呢?”
答:我们知道字符到字节必须经过转码,这个过程非常耗时,如果我们不知道编码类型就很容易出现乱码问题。所以I/O流提供了一个直接操作字符的接口,方便我们平时对字符进行流操作。

  • 传统I/O的性能问题
    • 1.多次内存复制
      在这里插入图片描述
    • 2.阻塞
      • 如何优化I/O操作
      • 1.使用缓冲区优化读写流操作
      • 2.使用DirectBuffer减少内存复制
      • 3.避免阻塞,优化I/O操作
  • 通道(Channel)
  • 多路复用器(Selector)

09 | 网络通信优化之序列化:避免使用Java序列化

两个服务之间要共享一个数据对象,就需要从对象转换成二进制流,通过网络传输,传送到对方服务,再转换回对象,供服务方法调用。这个编码和解码过程我们称之为序列化与反序列化。

在大量并发请求的情况下,如果序列化的速度慢,会导致请求响应时间增加;而序列化后的传输数据体积大,会导致网络吞吐量下降。所以一个优秀的序列化框架可以提高系统的整体性能。

  • Java序列化

    • Java序列化的缺陷
    • 1.无法跨语言
    • 2.易被攻击 ----> 那么后来是如何解决这个漏洞的呢?
    • 3.序列化后的流太大
    • 4.序列化性能太差
  • 使用Protobuf序列化替换Java序列化

目前业内优秀的序列化框架有很多,而且大部分都避免了Java默认序列化的一些缺陷。例如,最近几年比较流行的FastJson、Kryo、Protobuf、Hessian等。我们完全可以找一种替换掉Java序列化,这里我推荐使用Protobuf序列化框架。 Protobuf序列化原理

  • 这里拓展一点,我来讲下什么是Protocol Buffers存储格式以及它的实现原理。 具体看原文
  • Protobuf定义了一套自己的编码方式,几乎可以映射Java/Python等语言的所有基础数据类型。不同的编码方式对应不同的数据类型,还能采用不同的存储格式。如下图所示:
    在这里插入图片描述

10 | 网络通信优化之通信协议:如何优化RPC网络通信?

  • RPC通信是大型服务框架的核心

  • 我认为微服务的核心是远程通信和服务治理。
    目前,很多微服务框架中的服务通信是基于RPC通信实现的,在没有进行组件扩展的前提下,SpringCloud是基于Feign组件实现的RPC通信(基于Http+Json序列化实现),Dubbo是基于SPI扩展了很多RPC通信框架,包括RMI、Dubbo、Hessian等RPC通信框架(默认是Dubbo+Hessian序列化)。
    不同的业务场景下,RPC通信的选择和优化标准也不同。例如,开头我提到的我们部门在选择微服务框架时,选择了Dubbo。当时的选择标准就是RPC通信可以支持抢购类的高并发,在这个业务场景中,请求的特点是瞬时高峰、请求量大和传入、传出参数数据包较小。而Dubbo中的Dubbo协议就很好地支持了这个请求。
    在这里插入图片描述

  • 什么是RPC通信
    在这里插入图片描述
    RMI(Remote Method Invocation)是JDK中最先实现了RPC通信的框架之一,RMI的实现对建立分布式Java应用程序至关重要,是Java体系非常重要的底层技术,很多开源的RPC通信框架也是基于RMI实现原理设计出来的,包括Dubbo框架中也接入了RMI框架。接下来我们就一起了解下RMI的实现原理,看看它存在哪些性能瓶颈有待优化。

  • RMI:JDK自带的RPC通信框架

    • RMI的实现原理
    • RMI在高并发场景下的性能瓶颈
      • Java默认序列化
      • TCP短连接
      • 阻塞式网络I/O
  • 一个高并发场景下的RPC通信优化路径

    • 1.选择合适的通信协议
    • 2.使用单一长连接
    • 3.优化Socket通信
      • 实现非阻塞I/O
      • 高效的Reactor线程模型
      • 串行设计
      • 零拷贝
        除了以上这些优化,我们还可以针对套接字编程提供的一些TCP参数配置项,提高网络吞吐量,Netty可以基于ChannelOption来设置这些参数。
    • 4.量身定做报文格式
    • 5.编码、解码
    • 6.调整Linux的TCP参数设置选项

在一些并发场景比较多的系统中,我更偏向使用Dubbo实现的这一套RPC通信协议。Dubbo协议是建立的单一长连接通信,网络I/O为NIO非阻塞读写操作,更兼容了Kryo、FST、Protobuf等性能出众的序列化框架,在高并发、小对象传输的业务场景中非常实用。

11 | 答疑课堂:深入了解NIO的优化实现原理

Tomcat中经常被提到的一个调优就是修改线程的I/O模型。Tomcat 8.5版本之前,默认情况下使用的是BIO线程模型,如果在高负载、高并发的场景下,可以通过设置NIO线程模型,来提高系统的网络通信性能。

网络通信中,最底层的就是内核中的网络I/O模型了。随着技术的发展,操作系统内核的网络模型衍生出了五种I/O模型,《UNIX网络编程》一书将这五种I/O模型分为阻塞式I/O、非阻塞式I/O、I/O复用、信号驱动式I/O和异步I/O。每一种I/O模型的出现,都是基于前一种I/O模型的优化升级。

  • 网络I/O模型优化

    • 那阻塞到底发生在套接字(socket)通信的哪些环节呢?
  • 1.阻塞式I/O

    • connect阻塞
    • accept阻塞
    • read、write阻塞
  • 2.非阻塞式I/O
    使用fcntl可以把以上三种操作都设置为非阻塞操作。如果没有数据返回,就会直接返回一个EWOULDBLOCK或EAGAIN错误,此时进程就不会一直被阻塞。

  • 3.I/O复用
    如果使用用户线程轮询查看一个I/O操作的状态,在大量请求的情况下,这对于CPU的使用率无疑是种灾难。 那么除了这种方式,还有其它方式可以实现非阻塞I/O套接字吗?
    Linux提供了I/O复用函数select/poll/epoll,进程将一个或多个读操作通过系统调用函数,阻塞在函数操作上。这样,系统内核就可以帮我们侦测多个读操作是否处于就绪状态。

    • select()函数
    • poll()函数
    • epoll()函数
    • 通过以上代码,我们可以看到:epoll_ctl()函数中的epfd是由 epoll_create()函数生成的一个epoll专用文件描述符。op代表操作事件类型,fd表示关联文件描述符,event表示指定监听的事件类型。
  • 4.信号驱动式I/O

  • 5.异步I/O

  • 零拷贝

    • 线程模型优化
    • 1.单线程Reactor线程模型
    • 2.多线程Reactor线程模型
    • 3.主从Reactor线程模型
    • 基于线程模型的Tomcat参数调优

在这里插入图片描述

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值