Java并发编程实战 避免活跃性危险

10、避免活跃性风险

10.1 死锁

 

 

10.2 死锁避免与诊断

  • 找出什么地方将获取多个锁,然后对所有这些实例进行全局分析,从而确保它们在整个程序中获取锁的顺序都保持一致。

10.3 其他活跃性危险

  • 饥饿:当线程无法访问所需资源而不能继续执行时,就发生了饥饿。
  • 响应性:当某个线程长时间占有一个锁而其他想要访问这个容器的线程就必须等待很长时间。
  • 活锁:线程不断重复执行相同操作,引入随机性解决。

11、性能与可伸缩性

  • 避免不成熟的优化。
  • 在什么条件下运行得更快?考虑负载、数据量。这些条件在运行环境中是频繁发生的吗?性能提升的代价?

11.2 Amdahl定律

F是必须串行的部分,N是机器个数。
所以需要分析串行、并行部分占比。

11.3 线程引入的开销

  • Synchronized和volatile提供的可见性保证中会使用内存栅栏。内存栅栏可以刷新缓存,使缓存无效,刷新硬件的写缓冲。
  • 当线程无法获取某个锁或者由于某个条件等待或在IO操作上阻塞时,需要被挂起,在这个过程中将包含两次额外的上下文切换,以及所有必要地操作系统操作和缓存操作。

11.4 减少锁的竞争

  • 影响锁发生竞争的两个因素:锁的请求频率、每次持有该锁的时间。
  • 减少锁的范围、减小锁的请求频率、分段锁、避免热点域、读写锁原子变量替代锁、检测CPU利用率。

12、并发程序的测试

  • 测试点:吞吐量、响应性、可伸缩性

12.1 正确性

  • 与串行执行有相同结果

  • 使用Thread.yield将产生更多的上下文切换。

12.2 性能测试

基于栅栏定时器

12.3 避免性能测试陷阱

考虑垃圾回收、动态编译、不真实的竞争(考虑真正并发的地方)

posted on 2023-08-20 15:47  kaiker  阅读(13)  评论(0)    收藏  举报