01 | 如何制定性能调优标准?

 为什么要做性能调优?

02 | 如何制定性能调优策略?

 总结一下就是“测试 - 分析 - 调优”三步走

性能测试攻略:性能测试是提前发现性能瓶颈,保障系统性能稳定的必要措施

1. 微基准性能测试

2. 宏基准性能测试

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

 String 对象是如何实现的?

 

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

加餐 | 推荐几款常用的性能测试工具

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

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

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

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

 

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

1.复用io:

  select()函数:它的用途是,在超时时间内,监听用户感兴趣的文件描述符上的可读可写和异常事件的发生;

  poll()函数:在每次调用 select() 函数之前,系统需要把一个 fd 从用户态拷贝到内核态;

  epoll()函数:epoll 使用事件驱动的方式代替轮询扫描 fd;

  epoll 事先通过 epoll_ctl() 来注册一个文件描述符,将文件描述符存放到内核的一个事件表中,这个事件表是基于红黑树实现的,所以在大量 I/O 请求的场景下,插入和删除的性能比 select/poll 的数组 fd_set 要好,因此 epoll 的性能更胜一筹,而且不会受到 fd 数量的限制。

  epoll_ctl() 函数中的 epfd 是由 epoll_create() 函数生成的一个 epoll 专用文件描述符。op 代表操作事件类型,fd 表示关联文件描述符,event 表示指定监听的事件类型。

  零拷贝:epoll 函数中就是使用了 mmap 减少了内存拷贝,Linux 内核中的 mmap 函数可以代替 read、write 的 I/O 读写操作,实现用户空间和内核空间共享一个缓存数据

  (Java 的 NIO 编程中,则是使用到了 Direct Buffer 来实现内存的零拷贝,Java 直接在 JVM 内存空间之外开辟了一个物理内存空间,这样内核和用户进程都能共享一份缓存数据

 

线程模型优化:

      1. 单线程 Reactor 线程模型

  2. 多线程 Reactor 线程模型  

  3. 主从 Reactor 线程模型

Reactor 模式中有 2 个关键组成:

  Reactor:Reactor 在一个单独的线程中运行,负责监听和分发事件,分发给适当的处理程序来对 IO 事件做出反应

  Handlers:处理程序执行 I/O 事件要完成的实际事件

 

方案说明:

  • 1)Reactor 主线程 MainReactor 对象通过 Select 监控建立连接事件,收到事件后通过 Acceptor 接收,处理建立连接事件;
  • 2)Acceptor 处理建立连接事件后,MainReactor 将连接分配 Reactor 子线程给 SubReactor 进行处理;
  • 3)SubReactor 将连接加入连接队列进行监听,并创建一个 Handler 用于处理各种连接事件;
  • 4)当有新的事件发生时,SubReactor 会调用连接对应的 Handler 进行响应;
  • 5)Handler 通过 Read 读取数据后,会分发给后面的 Worker 线程池进行业务处理;
  • 6)Worker 线程池会分配独立的线程完成真正的业务处理,如何将响应结果发给 Handler 进行处理;
  • 7)Handler 收到响应结果后通过 Send 将响应结果返回给 Client。

 


优点:父线程与子线程的数据交互简单职责明确,父线程只需要接收新连接,子线程完成后续的业务处理。

父线程与子线程的数据交互简单,Reactor 主线程只需要把新连接传给子线程,子线程无需返回数据。

这种模型在许多项目中广泛使用,包括 Nginx 主从 Reactor 多进程模型,Memcached 主从多线程,Netty 主从多线程模型的支持。

 

1)bossGroup 线程池则只是在 Bind 某个端口后,获得其中一个线程作为 MainReactor,专门处理端口的 Accept 事件,每个端口对应一个 Boss 线程;

2)workerGroup 线程池会被各个 SubReactor 和 Worker 线程充分利用。

12 | 多线程之锁优化(上):深入了解Synchronized同步锁的优化方法

 

Synchronized 同步锁实现原理

通常 Synchronized 实现同步锁的方式有两种,一种是修饰方法,一种是修饰方法块

Synchronized 在修饰同步代码块时,是由 monitorenter 和 monitorexit 指令来实现同步的。进入 monitorenter 指令后,线程将持有 Monitor 对象,退出 monitorenter 指令后,线程将释放该 Monitor 对象。