Java线程提升性能解惑

问题

首先明确一个问题,什么是提升性能?所谓的提升性能就是用更少的资源去做更多的事情。
在Java中我们最常使用多线程来提升性能,但是多线程也存在如下问题

  • 线程间的协调
    • 加锁
    • 触发信号
    • 内存同步
      • 有竞争同步,需要关注调优。
      • 无竞争同步,无竞争同步,JVM会通过逸出分析,锁粒度粗化来优化。
  • 上下文切换
    造成: 可运行的线程数 > 处理器的数量
    处理: 分配最小执行时间,分担开销
    开销: 5000-10000个时钟周期(可通过vmstat查看上下文切换次数与在内核中执行时间所占的比例)

  • 线程的创建与销毁

  • 线程的调度 有了问题就要解决这些问题:多线程如何解决以上问题的存在,首先要分析程序是CPU密集型还是I/O密集型。
  • 更有效利用现有的处理资源
  • 出现新的处理资源时,使程序尽可能利用这些资源(可伸缩性)

为什么会出现阻塞:竞争失败的线程,有如下原因:

  • 无法获取某个锁
  • 在某个条件等待
  • 在等待IO

由于锁竞争会同时降低可伸缩性和导致上下文切换造成的性能损失。
非常有必要减少锁竞争

  • 减少锁持有时间
    • 缩小锁的范围,移出与锁无关的代码
    • 减少锁粒度,不过这步容易被JVM进行锁粗粒度优化
  • 降低锁的请求频率
    • 锁分解,把一个锁分解为两个锁
    • 锁分段,把一个锁分解为多个锁
  • 使用带有协调机制的的锁,比如使用并发容器、读写锁、不可变对象、原子变量等代替锁。

Amdahl定律指出可伸缩性与程序中串行执行的代码有关。但是在任何并发程序中都存在一些串行部分。通过之前提到的锁分段来降低锁粒度,因为分段的
数量可以随着处理器的数量增加而增加。

通过监控CPU负载可以判断CPU是否被充分利用,如果CPU利用不均匀,有些很忙碌,而有些则很空闲,说明计算由一小组线程完成的,而并没有利用到其他处理器。
有可能是如下几点造成的:

  • 负载不足
  • I/O密集型任务
  • 外部限制
  • 锁竞争